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

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 (323) 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 +1513 -3
  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/model.d.ts +153 -0
  15. package/dist/component/model.d.ts.map +1 -0
  16. package/dist/component/model.js +327 -0
  17. package/dist/component/model.js.map +1 -0
  18. package/dist/component/providers/sso.d.ts +1 -1
  19. package/dist/component/public/enterprise.d.ts +49 -0
  20. package/dist/component/public/enterprise.d.ts.map +1 -0
  21. package/dist/component/public/enterprise.js +450 -0
  22. package/dist/component/public/enterprise.js.map +1 -0
  23. package/dist/component/public/factors.d.ts +52 -0
  24. package/dist/component/public/factors.d.ts.map +1 -0
  25. package/dist/component/public/factors.js +285 -0
  26. package/dist/component/public/factors.js.map +1 -0
  27. package/dist/component/public/groups.d.ts +118 -0
  28. package/dist/component/public/groups.d.ts.map +1 -0
  29. package/dist/component/public/groups.js +599 -0
  30. package/dist/component/public/groups.js.map +1 -0
  31. package/dist/component/public/identity.d.ts +93 -0
  32. package/dist/component/public/identity.d.ts.map +1 -0
  33. package/dist/component/public/identity.js +426 -0
  34. package/dist/component/public/identity.js.map +1 -0
  35. package/dist/component/public/keys.d.ts +41 -0
  36. package/dist/component/public/keys.d.ts.map +1 -0
  37. package/dist/component/public/keys.js +157 -0
  38. package/dist/component/public/keys.js.map +1 -0
  39. package/dist/component/public/shared.d.ts +26 -0
  40. package/dist/component/public/shared.d.ts.map +1 -0
  41. package/dist/component/public/shared.js +32 -0
  42. package/dist/component/public/shared.js.map +1 -0
  43. package/dist/component/public.d.ts +9 -321
  44. package/dist/component/public.d.ts.map +1 -1
  45. package/dist/component/public.js +6 -2145
  46. package/dist/component/schema.d.ts +368 -258
  47. package/dist/component/schema.js +23 -27
  48. package/dist/component/schema.js.map +1 -1
  49. package/dist/component/server/auth.d.ts +42 -7
  50. package/dist/component/server/auth.d.ts.map +1 -1
  51. package/dist/component/server/auth.js +70 -6
  52. package/dist/component/server/auth.js.map +1 -1
  53. package/dist/component/server/cookies.js +3 -0
  54. package/dist/component/server/cookies.js.map +1 -1
  55. package/dist/component/server/db.js +1 -0
  56. package/dist/component/server/db.js.map +1 -1
  57. package/dist/component/server/device.js +3 -1
  58. package/dist/component/server/device.js.map +1 -1
  59. package/dist/component/server/domains/core.js +466 -0
  60. package/dist/component/server/domains/core.js.map +1 -0
  61. package/dist/component/server/domains/sso.js +689 -0
  62. package/dist/component/server/domains/sso.js.map +1 -0
  63. package/dist/component/server/factory.d.ts +136 -0
  64. package/dist/component/server/factory.d.ts.map +1 -0
  65. package/dist/component/server/factory.js +1128 -0
  66. package/dist/component/server/factory.js.map +1 -0
  67. package/dist/component/server/fx.js +2 -1
  68. package/dist/component/server/fx.js.map +1 -1
  69. package/dist/component/server/http.js +287 -0
  70. package/dist/component/server/http.js.map +1 -0
  71. package/dist/component/server/identity.js +13 -0
  72. package/dist/component/server/identity.js.map +1 -0
  73. package/dist/component/server/keys.js +4 -0
  74. package/dist/component/server/keys.js.map +1 -1
  75. package/dist/component/server/mutations/account.js +1 -1
  76. package/dist/component/server/mutations/index.js +2 -2
  77. package/dist/component/server/mutations/index.js.map +1 -1
  78. package/dist/component/server/mutations/invalidate.js +1 -1
  79. package/dist/component/server/mutations/oauth.js +10 -7
  80. package/dist/component/server/mutations/oauth.js.map +1 -1
  81. package/dist/component/server/mutations/refresh.js +1 -1
  82. package/dist/component/server/mutations/register.js +1 -1
  83. package/dist/component/server/mutations/retrieve.js +1 -1
  84. package/dist/component/server/mutations/signature.js +1 -1
  85. package/dist/component/server/mutations/store.js +6 -3
  86. package/dist/component/server/mutations/store.js.map +1 -1
  87. package/dist/component/server/mutations/verify.js +1 -1
  88. package/dist/component/server/oauth.js +3 -0
  89. package/dist/component/server/oauth.js.map +1 -1
  90. package/dist/component/server/passkey.js +3 -2
  91. package/dist/component/server/passkey.js.map +1 -1
  92. package/dist/component/server/provider.js +2 -0
  93. package/dist/component/server/provider.js.map +1 -1
  94. package/dist/component/server/providers.js +3 -0
  95. package/dist/component/server/providers.js.map +1 -1
  96. package/dist/component/server/ratelimit.js +3 -0
  97. package/dist/component/server/ratelimit.js.map +1 -1
  98. package/dist/component/server/redirects.js +2 -0
  99. package/dist/component/server/redirects.js.map +1 -1
  100. package/dist/component/server/refresh.js +5 -0
  101. package/dist/component/server/refresh.js.map +1 -1
  102. package/dist/component/server/sessions.js +5 -0
  103. package/dist/component/server/sessions.js.map +1 -1
  104. package/dist/component/server/signin.js +2 -1
  105. package/dist/component/server/signin.js.map +1 -1
  106. package/dist/component/server/sso.js +166 -19
  107. package/dist/component/server/sso.js.map +1 -1
  108. package/dist/component/server/tokens.js +1 -0
  109. package/dist/component/server/tokens.js.map +1 -1
  110. package/dist/component/server/totp.js +4 -2
  111. package/dist/component/server/totp.js.map +1 -1
  112. package/dist/component/server/types.d.ts +50 -35
  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 +1 -0
  116. package/dist/component/server/users.js.map +1 -1
  117. package/dist/component/server/utils.js +44 -2
  118. package/dist/component/server/utils.js.map +1 -1
  119. package/dist/providers/anonymous.d.ts +1 -1
  120. package/dist/providers/credentials.d.ts +1 -1
  121. package/dist/providers/password.d.ts +1 -1
  122. package/dist/providers/sso.d.ts +1 -1
  123. package/dist/providers/sso.js.map +1 -1
  124. package/dist/server/auth.d.ts +44 -9
  125. package/dist/server/auth.d.ts.map +1 -1
  126. package/dist/server/auth.js +70 -6
  127. package/dist/server/auth.js.map +1 -1
  128. package/dist/server/cookies.d.ts +1 -38
  129. package/dist/server/cookies.js +3 -0
  130. package/dist/server/cookies.js.map +1 -1
  131. package/dist/server/db.d.ts +1 -125
  132. package/dist/server/db.js +1 -0
  133. package/dist/server/db.js.map +1 -1
  134. package/dist/server/device.d.ts +1 -24
  135. package/dist/server/device.js +3 -1
  136. package/dist/server/device.js.map +1 -1
  137. package/dist/server/domains/core.d.ts +320 -0
  138. package/dist/server/domains/core.d.ts.map +1 -0
  139. package/dist/server/domains/core.js +466 -0
  140. package/dist/server/domains/core.js.map +1 -0
  141. package/dist/server/domains/sso.d.ts +340 -0
  142. package/dist/server/domains/sso.d.ts.map +1 -0
  143. package/dist/server/domains/sso.js +689 -0
  144. package/dist/server/domains/sso.js.map +1 -0
  145. package/dist/server/enterpriseValidators.d.ts +1 -0
  146. package/dist/server/enterpriseValidators.js +56 -0
  147. package/dist/server/enterpriseValidators.js.map +1 -0
  148. package/dist/server/factory.d.ts +136 -0
  149. package/dist/server/factory.d.ts.map +1 -0
  150. package/dist/server/factory.js +1128 -0
  151. package/dist/server/factory.js.map +1 -0
  152. package/dist/server/fx.d.ts +1 -16
  153. package/dist/server/fx.d.ts.map +1 -1
  154. package/dist/server/fx.js +1 -0
  155. package/dist/server/fx.js.map +1 -1
  156. package/dist/server/http.d.ts +59 -0
  157. package/dist/server/http.d.ts.map +1 -0
  158. package/dist/server/http.js +287 -0
  159. package/dist/server/http.js.map +1 -0
  160. package/dist/server/identity.d.ts +1 -0
  161. package/dist/server/identity.js +13 -0
  162. package/dist/server/identity.js.map +1 -0
  163. package/dist/server/index.d.ts +432 -1
  164. package/dist/server/index.d.ts.map +1 -1
  165. package/dist/server/index.js +486 -36
  166. package/dist/server/index.js.map +1 -1
  167. package/dist/server/keys.d.ts +1 -57
  168. package/dist/server/keys.js +4 -0
  169. package/dist/server/keys.js.map +1 -1
  170. package/dist/server/mutations/account.d.ts +7 -7
  171. package/dist/server/mutations/account.d.ts.map +1 -1
  172. package/dist/server/mutations/code.d.ts +13 -13
  173. package/dist/server/mutations/index.d.ts +107 -107
  174. package/dist/server/mutations/index.d.ts.map +1 -1
  175. package/dist/server/mutations/index.js +1 -1
  176. package/dist/server/mutations/index.js.map +1 -1
  177. package/dist/server/mutations/invalidate.d.ts +5 -5
  178. package/dist/server/mutations/oauth.d.ts +10 -10
  179. package/dist/server/mutations/oauth.d.ts.map +1 -1
  180. package/dist/server/mutations/oauth.js +9 -6
  181. package/dist/server/mutations/oauth.js.map +1 -1
  182. package/dist/server/mutations/refresh.d.ts +4 -4
  183. package/dist/server/mutations/register.d.ts +12 -12
  184. package/dist/server/mutations/register.d.ts.map +1 -1
  185. package/dist/server/mutations/retrieve.d.ts +1 -1
  186. package/dist/server/mutations/signature.d.ts +5 -5
  187. package/dist/server/mutations/signature.d.ts.map +1 -1
  188. package/dist/server/mutations/signin.d.ts +1 -1
  189. package/dist/server/mutations/signout.d.ts +1 -1
  190. package/dist/server/mutations/store.d.ts +3 -2
  191. package/dist/server/mutations/store.d.ts.map +1 -1
  192. package/dist/server/mutations/store.js +6 -3
  193. package/dist/server/mutations/store.js.map +1 -1
  194. package/dist/server/mutations/verifier.d.ts +1 -1
  195. package/dist/server/mutations/verify.d.ts +4 -4
  196. package/dist/server/oauth.d.ts +1 -59
  197. package/dist/server/oauth.js +3 -0
  198. package/dist/server/oauth.js.map +1 -1
  199. package/dist/server/passkey.d.ts.map +1 -1
  200. package/dist/server/passkey.js +3 -2
  201. package/dist/server/passkey.js.map +1 -1
  202. package/dist/server/provider.d.ts +1 -14
  203. package/dist/server/provider.d.ts.map +1 -1
  204. package/dist/server/provider.js +2 -0
  205. package/dist/server/provider.js.map +1 -1
  206. package/dist/server/providers.js +3 -0
  207. package/dist/server/providers.js.map +1 -1
  208. package/dist/server/ratelimit.d.ts +1 -22
  209. package/dist/server/ratelimit.js +3 -0
  210. package/dist/server/ratelimit.js.map +1 -1
  211. package/dist/server/redirects.d.ts +1 -10
  212. package/dist/server/redirects.js +2 -0
  213. package/dist/server/redirects.js.map +1 -1
  214. package/dist/server/refresh.d.ts +1 -37
  215. package/dist/server/refresh.js +5 -0
  216. package/dist/server/refresh.js.map +1 -1
  217. package/dist/server/sessions.d.ts +1 -28
  218. package/dist/server/sessions.js +5 -0
  219. package/dist/server/sessions.js.map +1 -1
  220. package/dist/server/signin.d.ts +1 -55
  221. package/dist/server/signin.js +2 -1
  222. package/dist/server/signin.js.map +1 -1
  223. package/dist/server/sso.d.ts +1 -348
  224. package/dist/server/sso.js +165 -18
  225. package/dist/server/sso.js.map +1 -1
  226. package/dist/server/templates.d.ts +1 -21
  227. package/dist/server/templates.js +1 -0
  228. package/dist/server/templates.js.map +1 -1
  229. package/dist/server/tokens.d.ts +1 -11
  230. package/dist/server/tokens.js +1 -0
  231. package/dist/server/tokens.js.map +1 -1
  232. package/dist/server/totp.d.ts +1 -23
  233. package/dist/server/totp.js +4 -2
  234. package/dist/server/totp.js.map +1 -1
  235. package/dist/server/types.d.ts +55 -71
  236. package/dist/server/types.d.ts.map +1 -1
  237. package/dist/server/types.js.map +1 -1
  238. package/dist/server/users.d.ts +1 -31
  239. package/dist/server/users.js +1 -0
  240. package/dist/server/users.js.map +1 -1
  241. package/dist/server/utils.d.ts +1 -27
  242. package/dist/server/utils.js +44 -2
  243. package/dist/server/utils.js.map +1 -1
  244. package/dist/server/version.d.ts +1 -1
  245. package/dist/server/version.js +1 -1
  246. package/dist/server/version.js.map +1 -1
  247. package/package.json +4 -5
  248. package/src/cli/bin.ts +5 -0
  249. package/src/cli/index.ts +22 -9
  250. package/src/cli/keys.ts +3 -0
  251. package/src/client/index.ts +36 -37
  252. package/src/component/_generated/api.ts +14 -0
  253. package/src/component/_generated/component.ts +1920 -3
  254. package/src/component/index.ts +2 -0
  255. package/src/component/model.ts +424 -0
  256. package/src/component/public/enterprise.ts +654 -0
  257. package/src/component/public/factors.ts +332 -0
  258. package/src/component/public/groups.ts +951 -0
  259. package/src/component/public/identity.ts +566 -0
  260. package/src/component/public/keys.ts +209 -0
  261. package/src/component/public/shared.ts +117 -0
  262. package/src/component/public.ts +5 -2965
  263. package/src/component/schema.ts +47 -57
  264. package/src/providers/sso.ts +1 -1
  265. package/src/server/auth.ts +192 -9
  266. package/src/server/cookies.ts +3 -0
  267. package/src/server/db.ts +3 -0
  268. package/src/server/device.ts +3 -1
  269. package/src/server/domains/core.ts +916 -0
  270. package/src/server/domains/sso.ts +1462 -0
  271. package/src/server/enterpriseValidators.ts +88 -0
  272. package/src/server/factory.ts +2168 -0
  273. package/src/server/fx.ts +1 -0
  274. package/src/server/http.ts +529 -0
  275. package/src/server/identity.ts +18 -0
  276. package/src/server/index.ts +712 -40
  277. package/src/server/keys.ts +4 -0
  278. package/src/server/mutations/index.ts +1 -1
  279. package/src/server/mutations/oauth.ts +36 -8
  280. package/src/server/mutations/store.ts +6 -3
  281. package/src/server/oauth.ts +6 -0
  282. package/src/server/passkey.ts +3 -2
  283. package/src/server/provider.ts +2 -0
  284. package/src/server/providers.ts +3 -0
  285. package/src/server/ratelimit.ts +3 -0
  286. package/src/server/redirects.ts +2 -0
  287. package/src/server/refresh.ts +5 -0
  288. package/src/server/sessions.ts +5 -0
  289. package/src/server/signin.ts +1 -0
  290. package/src/server/sso.ts +251 -17
  291. package/src/server/templates.ts +1 -0
  292. package/src/server/tokens.ts +1 -0
  293. package/src/server/totp.ts +4 -2
  294. package/src/server/types.ts +85 -77
  295. package/src/server/users.ts +1 -0
  296. package/src/server/utils.ts +71 -1
  297. package/src/server/version.ts +1 -1
  298. package/dist/component/public.js.map +0 -1
  299. package/dist/component/server/implementation.d.ts +0 -1264
  300. package/dist/component/server/implementation.d.ts.map +0 -1
  301. package/dist/component/server/implementation.js +0 -2365
  302. package/dist/component/server/implementation.js.map +0 -1
  303. package/dist/server/cookies.d.ts.map +0 -1
  304. package/dist/server/db.d.ts.map +0 -1
  305. package/dist/server/device.d.ts.map +0 -1
  306. package/dist/server/implementation.d.ts +0 -1264
  307. package/dist/server/implementation.d.ts.map +0 -1
  308. package/dist/server/implementation.js +0 -2365
  309. package/dist/server/implementation.js.map +0 -1
  310. package/dist/server/keys.d.ts.map +0 -1
  311. package/dist/server/oauth.d.ts.map +0 -1
  312. package/dist/server/ratelimit.d.ts.map +0 -1
  313. package/dist/server/redirects.d.ts.map +0 -1
  314. package/dist/server/refresh.d.ts.map +0 -1
  315. package/dist/server/sessions.d.ts.map +0 -1
  316. package/dist/server/signin.d.ts.map +0 -1
  317. package/dist/server/sso.d.ts.map +0 -1
  318. package/dist/server/templates.d.ts.map +0 -1
  319. package/dist/server/tokens.d.ts.map +0 -1
  320. package/dist/server/totp.d.ts.map +0 -1
  321. package/dist/server/users.d.ts.map +0 -1
  322. package/dist/server/utils.d.ts.map +0 -1
  323. package/src/server/implementation.ts +0 -5336
@@ -1,6 +1,24 @@
1
1
  import { defineSchema, defineTable } from "convex/server";
2
2
  import { v } from "convex/values";
3
3
 
4
+ import {
5
+ vApiKeyRateLimit,
6
+ vApiKeyRateLimitState,
7
+ vApiKeyScope,
8
+ vAuditActorType,
9
+ vAuditStatus,
10
+ vDeviceStatus,
11
+ vEnterprisePolicy,
12
+ vEnterpriseSecretKind,
13
+ vEnterpriseStatus,
14
+ vInviteStatus,
15
+ vScimResourceType,
16
+ vScimStatus,
17
+ vTag,
18
+ vWebhookDeliveryStatus,
19
+ vWebhookEndpointStatus,
20
+ } from "./model";
21
+
4
22
  /**
5
23
  * Schema for the auth component.
6
24
  *
@@ -166,11 +184,7 @@ export default defineSchema({
166
184
  /** Minimum polling interval in seconds. */
167
185
  interval: v.number(),
168
186
  /** Current status of this device authorization session. */
169
- status: v.union(
170
- v.literal("pending"),
171
- v.literal("authorized"),
172
- v.literal("denied"),
173
- ),
187
+ status: vDeviceStatus,
174
188
  /** Set when the user authorizes — links to the authorizing user. */
175
189
  userId: v.optional(v.id("User")),
176
190
  /** Set when the user authorizes — the session created for the device. */
@@ -201,7 +215,7 @@ export default defineSchema({
201
215
  type: v.optional(v.string()),
202
216
  parentGroupId: v.optional(v.id("Group")),
203
217
  /** Faceted classification tags. Normalized at write time (trimmed, lowercased). */
204
- tags: v.optional(v.array(v.object({ key: v.string(), value: v.string() }))),
218
+ tags: v.optional(v.array(vTag)),
205
219
  extend: v.optional(v.any()),
206
220
  })
207
221
  .index("slug", ["slug"])
@@ -253,12 +267,7 @@ export default defineSchema({
253
267
  email: v.optional(v.string()),
254
268
  tokenHash: v.string(),
255
269
  role: v.optional(v.string()),
256
- status: v.union(
257
- v.literal("pending"),
258
- v.literal("accepted"),
259
- v.literal("revoked"),
260
- v.literal("expired"),
261
- ),
270
+ status: vInviteStatus,
262
271
  expiresTime: v.optional(v.number()),
263
272
  acceptedByUserId: v.optional(v.id("User")),
264
273
  acceptedTime: v.optional(v.number()),
@@ -287,11 +296,8 @@ export default defineSchema({
287
296
  groupId: v.id("Group"),
288
297
  slug: v.optional(v.string()),
289
298
  name: v.optional(v.string()),
290
- status: v.union(
291
- v.literal("draft"),
292
- v.literal("active"),
293
- v.literal("disabled"),
294
- ),
299
+ status: vEnterpriseStatus,
300
+ policy: v.optional(vEnterprisePolicy),
295
301
  config: v.optional(v.any()),
296
302
  extend: v.optional(v.any()),
297
303
  })
@@ -313,21 +319,30 @@ export default defineSchema({
313
319
  .index("group_id", ["groupId"])
314
320
  .index("domain", ["domain"]),
315
321
 
322
+ /**
323
+ * Encrypted enterprise secrets stored separately from protocol config.
324
+ */
325
+ EnterpriseSecret: defineTable({
326
+ enterpriseId: v.id("Enterprise"),
327
+ groupId: v.id("Group"),
328
+ kind: vEnterpriseSecretKind,
329
+ ciphertext: v.string(),
330
+ updatedAt: v.number(),
331
+ })
332
+ .index("enterprise_id", ["enterpriseId"])
333
+ .index("enterprise_id_kind", ["enterpriseId", "kind"])
334
+ .index("group_id", ["groupId"]),
335
+
316
336
  /**
317
337
  * SCIM configuration for an enterprise tenant.
318
338
  */
319
339
  EnterpriseScimConfig: defineTable({
320
340
  enterpriseId: v.id("Enterprise"),
321
341
  groupId: v.id("Group"),
322
- status: v.union(
323
- v.literal("draft"),
324
- v.literal("active"),
325
- v.literal("disabled"),
326
- ),
342
+ status: vScimStatus,
327
343
  basePath: v.string(),
328
344
  tokenHash: v.string(),
329
345
  lastRotatedAt: v.optional(v.number()),
330
- deprovisionMode: v.optional(v.union(v.literal("soft"), v.literal("hard"))),
331
346
  extend: v.optional(v.any()),
332
347
  })
333
348
  .index("enterprise_id", ["enterpriseId"])
@@ -341,7 +356,7 @@ export default defineSchema({
341
356
  EnterpriseScimIdentity: defineTable({
342
357
  enterpriseId: v.id("Enterprise"),
343
358
  groupId: v.id("Group"),
344
- resourceType: v.union(v.literal("user"), v.literal("group")),
359
+ resourceType: vScimResourceType,
345
360
  externalId: v.string(),
346
361
  userId: v.optional(v.id("User")),
347
362
  mappedGroupId: v.optional(v.id("Group")),
@@ -356,6 +371,7 @@ export default defineSchema({
356
371
  "resourceType",
357
372
  "externalId",
358
373
  ])
374
+ .index("enterprise_id_user_id", ["enterpriseId", "userId"])
359
375
  .index("user_id", ["userId"])
360
376
  .index("mapped_group_id", ["mappedGroupId"]),
361
377
 
@@ -366,17 +382,11 @@ export default defineSchema({
366
382
  enterpriseId: v.id("Enterprise"),
367
383
  groupId: v.id("Group"),
368
384
  eventType: v.string(),
369
- actorType: v.union(
370
- v.literal("user"),
371
- v.literal("system"),
372
- v.literal("scim"),
373
- v.literal("api_key"),
374
- v.literal("webhook"),
375
- ),
385
+ actorType: vAuditActorType,
376
386
  actorId: v.optional(v.string()),
377
387
  subjectType: v.string(),
378
388
  subjectId: v.optional(v.string()),
379
- status: v.union(v.literal("success"), v.literal("failure")),
389
+ status: vAuditStatus,
380
390
  occurredAt: v.number(),
381
391
  requestId: v.optional(v.string()),
382
392
  ip: v.optional(v.string()),
@@ -393,7 +403,7 @@ export default defineSchema({
393
403
  enterpriseId: v.id("Enterprise"),
394
404
  groupId: v.id("Group"),
395
405
  url: v.string(),
396
- status: v.union(v.literal("active"), v.literal("disabled")),
406
+ status: vWebhookEndpointStatus,
397
407
  secretHash: v.string(),
398
408
  subscriptions: v.array(v.string()),
399
409
  createdByUserId: v.optional(v.id("User")),
@@ -414,12 +424,7 @@ export default defineSchema({
414
424
  endpointId: v.id("EnterpriseWebhookEndpoint"),
415
425
  auditEventId: v.optional(v.id("EnterpriseAuditEvent")),
416
426
  eventType: v.string(),
417
- status: v.union(
418
- v.literal("pending"),
419
- v.literal("processing"),
420
- v.literal("delivered"),
421
- v.literal("failed"),
422
- ),
427
+ status: vWebhookDeliveryStatus,
423
428
  attemptCount: v.number(),
424
429
  nextAttemptAt: v.number(),
425
430
  lastAttemptAt: v.optional(v.number()),
@@ -454,26 +459,11 @@ export default defineSchema({
454
459
  /** User-assigned name (e.g. "CI Pipeline", "Production API"). */
455
460
  name: v.string(),
456
461
  /** Scoped permissions: [{ resource: "users", actions: ["read", "list"] }]. */
457
- scopes: v.array(
458
- v.object({
459
- resource: v.string(),
460
- actions: v.array(v.string()),
461
- }),
462
- ),
462
+ scopes: v.array(vApiKeyScope),
463
463
  /** Optional per-key rate limit configuration. */
464
- rateLimit: v.optional(
465
- v.object({
466
- maxRequests: v.number(),
467
- windowMs: v.number(),
468
- }),
469
- ),
464
+ rateLimit: v.optional(vApiKeyRateLimit),
470
465
  /** Rate limit state tracking (token-bucket). */
471
- rateLimitState: v.optional(
472
- v.object({
473
- attemptsLeft: v.number(),
474
- lastAttemptTime: v.number(),
475
- }),
476
- ),
466
+ rateLimitState: v.optional(vApiKeyRateLimitState),
477
467
  /** Expiration timestamp. Null/undefined = never expires. */
478
468
  expiresAt: v.optional(v.number()),
479
469
  lastUsedAt: v.optional(v.number()),
@@ -14,7 +14,7 @@
14
14
  * });
15
15
  *
16
16
  * // auth.sso is now available
17
- * await auth.sso.oidc.configure(ctx, { enterpriseId, clientId, ... });
17
+ * await auth.sso.admin.oidc.configure(ctx, { enterpriseId, clientId, ... });
18
18
  * ```
19
19
  *
20
20
  * Without `new SSO()` in the providers list, `auth.sso` is not
@@ -8,9 +8,9 @@ import type { UserIdentity } from "convex/server";
8
8
  import type { GenericId } from "convex/values";
9
9
 
10
10
  import type { AuthApiRefs } from "../client/index";
11
+ import { Auth as AuthFactory } from "./factory";
11
12
  import { Fx } from "./fx";
12
13
  import { AuthError } from "./fx";
13
- import { Auth as AuthFactory } from "./implementation";
14
14
  import type { Doc } from "./types";
15
15
  import type {
16
16
  AuthProviderConfig,
@@ -47,14 +47,58 @@ export type AuthApiBase = {
47
47
  http: ReturnType<typeof AuthFactory>["auth"]["http"];
48
48
  };
49
49
 
50
- /** Auth API with SSO namespace — present only when `new SSO()` is in providers. */
50
+ type InternalSsoApi = ReturnType<typeof AuthFactory>["auth"]["sso"];
51
+
52
+ type PublicSsoAdminApi = {
53
+ connection: InternalSsoApi["connection"] & {
54
+ domain: {
55
+ list: InternalSsoApi["domain"]["list"];
56
+ validate: InternalSsoApi["domain"]["validate"];
57
+ set: (
58
+ ctx: Parameters<InternalSsoApi["connection"]["create"]>[0],
59
+ enterpriseId: string,
60
+ domains: Array<{
61
+ domain: string;
62
+ isPrimary?: boolean;
63
+ verifiedAt?: number;
64
+ }>,
65
+ ) => Promise<void>;
66
+ };
67
+ };
68
+ oidc: Omit<InternalSsoApi["oidc"], "signIn">;
69
+ saml: Omit<InternalSsoApi["saml"], "metadata">;
70
+ policy: InternalSsoApi["policy"];
71
+ audit: {
72
+ list: InternalSsoApi["audit"]["list"];
73
+ };
74
+ webhook: {
75
+ endpoint: InternalSsoApi["webhook"]["endpoint"];
76
+ };
77
+ };
78
+
79
+ type PublicSsoClientApi = {
80
+ signIn: InternalSsoApi["oidc"]["signIn"];
81
+ metadata: InternalSsoApi["saml"]["metadata"];
82
+ };
83
+
84
+ type PublicSsoApi = {
85
+ admin: PublicSsoAdminApi;
86
+ client: PublicSsoClientApi;
87
+ };
88
+
89
+ type PublicScimApi = {
90
+ admin: Omit<InternalSsoApi["scim"], "getConfigByToken" | "identity">;
91
+ };
92
+
93
+ /** Auth API with enterprise namespaces — present only when `new SSO()` is in providers. */
51
94
  export type AuthApi = AuthApiBase & {
52
- sso: ReturnType<typeof AuthFactory>["auth"]["sso"];
95
+ sso: PublicSsoApi;
96
+ scim: PublicScimApi;
53
97
  };
54
98
 
55
99
  /**
56
100
  * The return type of `createAuth`. Conditional namespaces:
57
- * - `auth.sso` — only when `new SSO()` is in providers
101
+ * - `auth.sso` and `auth.scim` — only when `new SSO()` is in providers
58
102
  * - `auth.clientApi` — typed API refs for the client SDK with capabilities
59
103
  */
60
104
  export type ConvexAuthResult<P extends AuthProviderConfig[]> =
@@ -72,7 +116,7 @@ export type ConvexAuthResult<P extends AuthProviderConfig[]> =
72
116
  * // Frontend
73
117
  * import type { auth } from "../convex/auth";
74
118
  * import type { InferClientApi } from "@robelest/convex-auth/component";
75
- * const c = client<InferClientApi<typeof auth>>({ convex, api: { ... } });
119
+ * const c = client<InferClientApi<typeof auth>>({ convex, api: api.auth });
76
120
  * ```
77
121
  */
78
122
  export type InferClientApi<T> =
@@ -94,9 +138,9 @@ export type AuthLike = Pick<AuthApiBase, "user">;
94
138
  /**
95
139
  * Create an auth API object.
96
140
  *
97
- * When `new SSO()` is included in providers, `auth.sso` is available
98
- * on the returned object. Without it, `auth.sso` is absent and
99
- * accessing it is a TypeScript compile error.
141
+ * When `new SSO()` is included in providers, `auth.sso` and `auth.scim`
142
+ * are available on the returned object. Without it, those namespaces are
143
+ * absent and accessing them is a TypeScript compile error.
100
144
  */
101
145
  export function createAuth<P extends AuthProviderConfig[]>(
102
146
  component: ConvexAuthConfig["component"],
@@ -107,6 +151,138 @@ export function createAuth<P extends AuthProviderConfig[]>(
107
151
  component,
108
152
  providers: [...config.providers],
109
153
  });
154
+ const {
155
+ domain: domainApi,
156
+ scim: scimApi,
157
+ connection: connectionApi,
158
+ audit: auditApi,
159
+ webhook: webhookApi,
160
+ oidc: oidcApi,
161
+ saml: samlApi,
162
+ ...restSso
163
+ } = authResult.auth.sso as InternalSsoApi;
164
+
165
+ type SetEnterpriseDomains = PublicSsoAdminApi["connection"]["domain"]["set"];
166
+ type EnterpriseDomainInput = Array<{
167
+ domain: string;
168
+ isPrimary?: boolean;
169
+ verifiedAt?: number;
170
+ }>;
171
+ const setEnterpriseDomains: PublicSsoAdminApi["connection"]["domain"]["set"] =
172
+ async (
173
+ ctx: Parameters<SetEnterpriseDomains>[0],
174
+ enterpriseId: Parameters<SetEnterpriseDomains>[1],
175
+ domains: EnterpriseDomainInput,
176
+ ) => {
177
+ const enterprise = await connectionApi.get(ctx, enterpriseId);
178
+ if (enterprise === null) {
179
+ throw new AuthError(
180
+ "INVALID_PARAMETERS",
181
+ "Enterprise not found.",
182
+ ).toConvexError();
183
+ }
184
+
185
+ const normalized = domains.map((entry: (typeof domains)[number]) => ({
186
+ ...entry,
187
+ domain: entry.domain.trim().toLowerCase(),
188
+ }));
189
+ const deduped = new Map<string, (typeof normalized)[number]>();
190
+ for (const entry of normalized) {
191
+ if (entry.domain.length === 0) {
192
+ throw new AuthError(
193
+ "INVALID_PARAMETERS",
194
+ "Domain must not be empty.",
195
+ ).toConvexError();
196
+ }
197
+ if (deduped.has(entry.domain)) {
198
+ throw new AuthError(
199
+ "INVALID_PARAMETERS",
200
+ `Duplicate domain: ${entry.domain}`,
201
+ ).toConvexError();
202
+ }
203
+ deduped.set(entry.domain, entry);
204
+ }
205
+
206
+ const nextDomains = [...deduped.values()];
207
+ const primaryCount = nextDomains.filter(
208
+ (entry) => entry.isPrimary,
209
+ ).length;
210
+ if (primaryCount > 1) {
211
+ throw new AuthError(
212
+ "INVALID_PARAMETERS",
213
+ "Only one primary domain may be set.",
214
+ ).toConvexError();
215
+ }
216
+ if (nextDomains.length > 0 && primaryCount === 0) {
217
+ nextDomains[0] = { ...nextDomains[0], isPrimary: true };
218
+ }
219
+
220
+ const currentDomains = await domainApi.list(ctx, enterpriseId);
221
+ const currentByDomain = new Map<string, (typeof currentDomains)[number]>(
222
+ currentDomains.map((entry: (typeof currentDomains)[number]) => [
223
+ entry.domain.toLowerCase(),
224
+ entry,
225
+ ]),
226
+ );
227
+
228
+ for (const existing of currentDomains) {
229
+ if (!deduped.has(existing.domain.toLowerCase())) {
230
+ await domainApi.remove(ctx, existing._id);
231
+ }
232
+ }
233
+
234
+ for (const nextDomain of nextDomains) {
235
+ const current = currentByDomain.get(nextDomain.domain);
236
+ if (
237
+ current &&
238
+ current.isPrimary === Boolean(nextDomain.isPrimary) &&
239
+ current.verifiedAt === (nextDomain.verifiedAt ?? current.verifiedAt)
240
+ ) {
241
+ continue;
242
+ }
243
+ if (current) {
244
+ await domainApi.remove(ctx, current._id);
245
+ }
246
+ await domainApi.add(ctx, {
247
+ enterpriseId: enterprise._id,
248
+ groupId: enterprise.groupId,
249
+ domain: nextDomain.domain,
250
+ isPrimary: nextDomain.isPrimary,
251
+ verifiedAt: nextDomain.verifiedAt ?? current?.verifiedAt,
252
+ });
253
+ }
254
+ };
255
+
256
+ const publicSso: PublicSsoApi = {
257
+ admin: {
258
+ ...restSso,
259
+ oidc: {
260
+ ...oidcApi,
261
+ },
262
+ saml: {
263
+ ...samlApi,
264
+ },
265
+ connection: {
266
+ ...connectionApi,
267
+ domain: {
268
+ list: domainApi.list,
269
+ validate: domainApi.validate,
270
+ set: setEnterpriseDomains,
271
+ },
272
+ },
273
+ policy: restSso.policy,
274
+ audit: {
275
+ list: auditApi.list,
276
+ },
277
+ webhook: {
278
+ endpoint: webhookApi.endpoint,
279
+ },
280
+ },
281
+ client: {
282
+ signIn: oidcApi.signIn,
283
+ metadata: samlApi.metadata,
284
+ },
285
+ };
110
286
 
111
287
  return {
112
288
  signIn: authResult.signIn,
@@ -120,7 +296,14 @@ export function createAuth<P extends AuthProviderConfig[]>(
120
296
  member: authResult.auth.member,
121
297
  invite: authResult.auth.invite,
122
298
  key: authResult.auth.key,
123
- sso: authResult.auth.sso,
299
+ sso: publicSso,
300
+ scim: {
301
+ admin: {
302
+ configure: scimApi.configure,
303
+ get: scimApi.get,
304
+ validate: scimApi.validate,
305
+ },
306
+ },
124
307
  http: authResult.auth.http,
125
308
  } as ConvexAuthResult<P>;
126
309
  }
@@ -1,5 +1,6 @@
1
1
  import { isLocalHost } from "./utils";
2
2
 
3
+ /** @internal */
3
4
  export const SHARED_COOKIE_OPTIONS = {
4
5
  httpOnly: true,
5
6
  sameSite: "none" as const,
@@ -9,6 +10,7 @@ export const SHARED_COOKIE_OPTIONS = {
9
10
  };
10
11
 
11
12
  const REDIRECT_MAX_AGE = 60 * 15; // 15 minutes in seconds
13
+ /** @internal */
12
14
  export function redirectToParamCookie(providerId: string, redirectTo: string) {
13
15
  return {
14
16
  name: redirectToParamCookieName(providerId),
@@ -17,6 +19,7 @@ export function redirectToParamCookie(providerId: string, redirectTo: string) {
17
19
  };
18
20
  }
19
21
 
22
+ /** @internal */
20
23
  export function useRedirectToParam(
21
24
  providerId: string,
22
25
  cookies: Record<string, string | undefined>,
package/src/server/db.ts CHANGED
@@ -56,10 +56,13 @@ type AuthComponentApiLike = {
56
56
  };
57
57
  };
58
58
 
59
+ /** @internal */
59
60
  export type AuthDbConfig = { component: AuthComponentApiLike };
60
61
 
62
+ /** @internal */
61
63
  export type AuthDb = ReturnType<typeof authDb>;
62
64
 
65
+ /** @internal */
63
66
  export function authDb(ctx: CtxLike, config: AuthDbConfig) {
64
67
  const component = config.component;
65
68
  return {
@@ -13,6 +13,7 @@
13
13
  import { Fx } from "@robelest/fx";
14
14
 
15
15
  import { AuthError } from "./fx";
16
+ import { userIdFromIdentitySubject } from "./identity";
16
17
  import { callSignIn } from "./mutations/index";
17
18
  import { DeviceProviderConfig, GenericActionCtxWithAuthConfig } from "./types";
18
19
  import {
@@ -63,6 +64,7 @@ type DeviceResult =
63
64
  }
64
65
  | { kind: "signedIn"; signedIn: SessionInfo | null };
65
66
 
67
+ /** @internal */
66
68
  export const handleDevice = (
67
69
  ctx: EnrichedActionCtx,
68
70
  provider: DeviceProviderConfig,
@@ -187,7 +189,7 @@ export const handleDevice = (
187
189
  );
188
190
  }
189
191
 
190
- const userId = identity.subject.split("|")[0]!;
192
+ const userId = userIdFromIdentitySubject(identity.subject);
191
193
  const doc = await queryDeviceByUserCode(ctx, params.userCode);
192
194
  if (doc === null) {
193
195
  throw new AuthError("DEVICE_INVALID_USER_CODE");