@estifanos-sh/convex-auth 0.0.2 → 0.0.4

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 (438) hide show
  1. package/README.md +29 -6
  2. package/dist/bin.js +2 -34
  3. package/dist/browser/index.d.ts +2 -2
  4. package/dist/browser/index.d.ts.map +1 -1
  5. package/dist/browser/index.js +15 -9
  6. package/dist/browser/index.js.map +1 -1
  7. package/dist/client/core/types.d.ts +68 -97
  8. package/dist/client/core/types.d.ts.map +1 -1
  9. package/dist/client/core/types.js.map +1 -1
  10. package/dist/client/errors.d.ts +15 -0
  11. package/dist/client/errors.d.ts.map +1 -0
  12. package/dist/client/errors.js +8 -1
  13. package/dist/client/errors.js.map +1 -1
  14. package/dist/client/factors/device.js +4 -4
  15. package/dist/client/factors/device.js.map +1 -1
  16. package/dist/client/factors/totp.js +20 -12
  17. package/dist/client/factors/totp.js.map +1 -1
  18. package/dist/client/factors/webauthn.js +6 -2
  19. package/dist/client/factors/webauthn.js.map +1 -1
  20. package/dist/client/index.d.ts +6 -3
  21. package/dist/client/index.d.ts.map +1 -1
  22. package/dist/client/index.js +13 -10
  23. package/dist/client/index.js.map +1 -1
  24. package/dist/component/_generated/api.d.ts +13 -3
  25. package/dist/component/_generated/api.d.ts.map +1 -1
  26. package/dist/component/_generated/api.js.map +1 -1
  27. package/dist/component/_generated/component.d.ts +365 -74
  28. package/dist/component/_generated/component.d.ts.map +1 -1
  29. package/dist/component/_generated/dataModel.d.ts +2 -2
  30. package/dist/component/_generated/dataModel.d.ts.map +1 -1
  31. package/dist/component/_generated/server.d.ts +13 -2
  32. package/dist/component/_generated/server.d.ts.map +1 -1
  33. package/dist/component/_generated/server.js +2 -1
  34. package/dist/component/_generated/server.js.map +1 -1
  35. package/dist/component/account.d.ts +52 -38
  36. package/dist/component/account.d.ts.map +1 -1
  37. package/dist/component/account.js +42 -23
  38. package/dist/component/account.js.map +1 -1
  39. package/dist/component/batch.d.ts +3 -0
  40. package/dist/component/batch.d.ts.map +1 -0
  41. package/dist/component/batch.js +17 -0
  42. package/dist/component/batch.js.map +1 -0
  43. package/dist/component/connection/audit.d.ts +30 -27
  44. package/dist/component/connection/audit.d.ts.map +1 -1
  45. package/dist/component/connection/audit.js +16 -23
  46. package/dist/component/connection/audit.js.map +1 -1
  47. package/dist/component/connection/cache.d.ts +6 -6
  48. package/dist/component/connection/cache.js +0 -1
  49. package/dist/component/connection/cache.js.map +1 -1
  50. package/dist/component/connection/domain/verification.d.ts +19 -19
  51. package/dist/component/connection/domain/verification.js +1 -2
  52. package/dist/component/connection/domain/verification.js.map +1 -1
  53. package/dist/component/connection/domain.d.ts +20 -20
  54. package/dist/component/connection/domain.js +1 -2
  55. package/dist/component/connection/domain.js.map +1 -1
  56. package/dist/component/connection/saml/assertion.d.ts +4 -4
  57. package/dist/component/connection/saml/assertion.js +0 -1
  58. package/dist/component/connection/saml/assertion.js.map +1 -1
  59. package/dist/component/connection/saml/request.d.ts +8 -9
  60. package/dist/component/connection/saml/request.d.ts.map +1 -1
  61. package/dist/component/connection/saml/request.js +0 -2
  62. package/dist/component/connection/saml/request.js.map +1 -1
  63. package/dist/component/connection/scim/config.d.ts +13 -13
  64. package/dist/component/connection/scim/config.d.ts.map +1 -1
  65. package/dist/component/connection/scim/config.js +2 -2
  66. package/dist/component/connection/scim/config.js.map +1 -1
  67. package/dist/component/connection/scim/identity.d.ts +122 -61
  68. package/dist/component/connection/scim/identity.d.ts.map +1 -1
  69. package/dist/component/connection/scim/identity.js +408 -60
  70. package/dist/component/connection/scim/identity.js.map +1 -1
  71. package/dist/component/connection/secret.d.ts +15 -15
  72. package/dist/component/connection/secret.d.ts.map +1 -1
  73. package/dist/component/connection/secret.js +2 -2
  74. package/dist/component/connection/secret.js.map +1 -1
  75. package/dist/component/connection/webhook/delivery.d.ts +69 -53
  76. package/dist/component/connection/webhook/delivery.d.ts.map +1 -1
  77. package/dist/component/connection/webhook/delivery.js +129 -172
  78. package/dist/component/connection/webhook/delivery.js.map +1 -1
  79. package/dist/component/connection/webhook/endpoint.d.ts +21 -21
  80. package/dist/component/connection/webhook/endpoint.d.ts.map +1 -1
  81. package/dist/component/connection/webhook/endpoint.js +2 -2
  82. package/dist/component/connection/webhook/endpoint.js.map +1 -1
  83. package/dist/component/connection/webhook/events.d.ts +26 -0
  84. package/dist/component/connection/webhook/events.d.ts.map +1 -0
  85. package/dist/component/connection/webhook/events.js +39 -0
  86. package/dist/component/connection/webhook/events.js.map +1 -0
  87. package/dist/component/connection.d.ts +39 -39
  88. package/dist/component/connection.d.ts.map +1 -1
  89. package/dist/component/connection.js +9 -9
  90. package/dist/component/connection.js.map +1 -1
  91. package/dist/component/context.d.ts +115 -0
  92. package/dist/component/context.d.ts.map +1 -0
  93. package/dist/component/context.js +49 -0
  94. package/dist/component/context.js.map +1 -0
  95. package/dist/component/convex.config.d.ts +2 -2
  96. package/dist/component/crons.d.ts +2 -2
  97. package/dist/component/documents.d.ts +1244 -0
  98. package/dist/component/documents.d.ts.map +1 -0
  99. package/dist/component/documents.js +44 -0
  100. package/dist/component/documents.js.map +1 -0
  101. package/dist/component/event.d.ts +142 -141
  102. package/dist/component/event.d.ts.map +1 -1
  103. package/dist/component/event.js +90 -119
  104. package/dist/component/event.js.map +1 -1
  105. package/dist/component/eventstream.d.ts +30 -0
  106. package/dist/component/eventstream.d.ts.map +1 -0
  107. package/dist/component/eventstream.js +60 -0
  108. package/dist/component/eventstream.js.map +1 -0
  109. package/dist/component/factor/device.d.ts +25 -24
  110. package/dist/component/factor/device.d.ts.map +1 -1
  111. package/dist/component/factor/device.js +7 -4
  112. package/dist/component/factor/device.js.map +1 -1
  113. package/dist/component/factor/passkey.d.ts +173 -85
  114. package/dist/component/factor/passkey.d.ts.map +1 -1
  115. package/dist/component/factor/passkey.js +138 -27
  116. package/dist/component/factor/passkey.js.map +1 -1
  117. package/dist/component/factor/totp.d.ts +56 -50
  118. package/dist/component/factor/totp.d.ts.map +1 -1
  119. package/dist/component/factor/totp.js +6 -5
  120. package/dist/component/factor/totp.js.map +1 -1
  121. package/dist/component/group/active.d.ts +326 -22
  122. package/dist/component/group/active.d.ts.map +1 -1
  123. package/dist/component/group/active.js +22 -13
  124. package/dist/component/group/active.js.map +1 -1
  125. package/dist/component/group/invite.d.ts +30 -30
  126. package/dist/component/group/invite.d.ts.map +1 -1
  127. package/dist/component/group/invite.js +2 -2
  128. package/dist/component/group/invite.js.map +1 -1
  129. package/dist/component/group/member.d.ts +36 -36
  130. package/dist/component/group/member.d.ts.map +1 -1
  131. package/dist/component/group/member.js +5 -3
  132. package/dist/component/group/member.js.map +1 -1
  133. package/dist/component/group.d.ts +49 -64
  134. package/dist/component/group.d.ts.map +1 -1
  135. package/dist/component/group.js +5 -3
  136. package/dist/component/group.js.map +1 -1
  137. package/dist/component/http.d.ts +2 -2
  138. package/dist/component/index.d.ts +0 -10
  139. package/dist/component/index.js +1 -3
  140. package/dist/component/limits.d.ts +5 -4
  141. package/dist/component/limits.d.ts.map +1 -1
  142. package/dist/component/limits.js +7 -4
  143. package/dist/component/limits.js.map +1 -1
  144. package/dist/component/maintenance.d.ts +6 -3
  145. package/dist/component/maintenance.d.ts.map +1 -1
  146. package/dist/component/maintenance.js +45 -6
  147. package/dist/component/maintenance.js.map +1 -1
  148. package/dist/component/model.d.ts +847 -1723
  149. package/dist/component/model.d.ts.map +1 -1
  150. package/dist/component/model.js +28 -317
  151. package/dist/component/model.js.map +1 -1
  152. package/dist/component/modules.d.ts +11 -5
  153. package/dist/component/modules.d.ts.map +1 -1
  154. package/dist/component/modules.js +4 -1
  155. package/dist/component/modules.js.map +1 -1
  156. package/dist/component/oauth/client.d.ts +20 -20
  157. package/dist/component/oauth/client.d.ts.map +1 -1
  158. package/dist/component/oauth/client.js +2 -2
  159. package/dist/component/oauth/client.js.map +1 -1
  160. package/dist/component/oauth/code.d.ts +14 -14
  161. package/dist/component/oauth/code.js +1 -2
  162. package/dist/component/oauth/code.js.map +1 -1
  163. package/dist/component/oauth/refresh.d.ts +20 -20
  164. package/dist/component/oauth/refresh.js +1 -2
  165. package/dist/component/oauth/refresh.js.map +1 -1
  166. package/dist/component/schema.d.ts +1148 -607
  167. package/dist/component/schema.d.ts.map +1 -1
  168. package/dist/component/schema.js +43 -15
  169. package/dist/component/schema.js.map +1 -1
  170. package/dist/component/session.d.ts +68 -32
  171. package/dist/component/session.d.ts.map +1 -1
  172. package/dist/component/session.js +118 -34
  173. package/dist/component/session.js.map +1 -1
  174. package/dist/component/token/continuation.d.ts +47 -18
  175. package/dist/component/token/continuation.d.ts.map +1 -1
  176. package/dist/component/token/continuation.js +76 -18
  177. package/dist/component/token/continuation.js.map +1 -1
  178. package/dist/component/token/enrollment.d.ts +42 -0
  179. package/dist/component/token/enrollment.d.ts.map +1 -0
  180. package/dist/component/token/enrollment.js +57 -0
  181. package/dist/component/token/enrollment.js.map +1 -0
  182. package/dist/component/token/pkce.d.ts +31 -24
  183. package/dist/component/token/pkce.d.ts.map +1 -1
  184. package/dist/component/token/pkce.js +15 -20
  185. package/dist/component/token/pkce.js.map +1 -1
  186. package/dist/component/token/refresh.d.ts +42 -35
  187. package/dist/component/token/refresh.d.ts.map +1 -1
  188. package/dist/component/token/refresh.js +16 -8
  189. package/dist/component/token/refresh.js.map +1 -1
  190. package/dist/component/token/verification.d.ts +34 -30
  191. package/dist/component/token/verification.d.ts.map +1 -1
  192. package/dist/component/token/verification.js +7 -6
  193. package/dist/component/token/verification.js.map +1 -1
  194. package/dist/component/user/email.d.ts +21 -21
  195. package/dist/component/user/email.d.ts.map +1 -1
  196. package/dist/component/user/email.js +2 -2
  197. package/dist/component/user/email.js.map +1 -1
  198. package/dist/component/user/key.d.ts +36 -36
  199. package/dist/component/user/key.d.ts.map +1 -1
  200. package/dist/component/user/key.js +2 -2
  201. package/dist/component/user/key.js.map +1 -1
  202. package/dist/component/user.d.ts +52 -48
  203. package/dist/component/user.d.ts.map +1 -1
  204. package/dist/component/user.js +157 -36
  205. package/dist/component/user.js.map +1 -1
  206. package/dist/expo/index.d.ts +4 -4
  207. package/dist/expo/index.d.ts.map +1 -1
  208. package/dist/expo/index.js +20 -13
  209. package/dist/expo/index.js.map +1 -1
  210. package/dist/node_modules/.pnpm/@opentelemetry_sdk-logs@0.214.0_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-logs/build/src/export/ReadableLogRecord.d.ts +2 -2
  211. package/dist/node_modules/.pnpm/@opentelemetry_sdk-logs@0.214.0_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-logs/build/src/export/SdkLogRecord.d.ts +1 -1
  212. package/dist/node_modules/.pnpm/@opentelemetry_sdk-metrics@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-metrics/build/src/MeterProvider.d.ts +2 -2
  213. package/dist/node_modules/.pnpm/@opentelemetry_sdk-metrics@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-metrics/build/src/export/MetricData.d.ts +1 -1
  214. package/dist/node_modules/.pnpm/@opentelemetry_sdk-trace-base@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-trace-base/build/src/Span.d.ts +1 -1
  215. package/dist/node_modules/.pnpm/@opentelemetry_sdk-trace-base@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-trace-base/build/src/export/ReadableSpan.d.ts +1 -1
  216. package/dist/node_modules/.pnpm/@opentelemetry_sdk-trace-base@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-trace-base/build/src/types.d.ts +1 -1
  217. package/dist/otel.d.ts +1 -1
  218. package/dist/providers/anonymous.d.ts +11 -5
  219. package/dist/providers/anonymous.d.ts.map +1 -1
  220. package/dist/providers/anonymous.js +4 -1
  221. package/dist/providers/anonymous.js.map +1 -1
  222. package/dist/providers/apple.d.ts +1 -1
  223. package/dist/providers/apple.js +19 -4
  224. package/dist/providers/apple.js.map +1 -1
  225. package/dist/providers/credentials.d.ts +22 -14
  226. package/dist/providers/credentials.d.ts.map +1 -1
  227. package/dist/providers/credentials.js +2 -0
  228. package/dist/providers/credentials.js.map +1 -1
  229. package/dist/providers/custom.d.ts +3 -3
  230. package/dist/providers/custom.d.ts.map +1 -1
  231. package/dist/providers/custom.js.map +1 -1
  232. package/dist/providers/email.d.ts +3 -3
  233. package/dist/providers/email.d.ts.map +1 -1
  234. package/dist/providers/email.js.map +1 -1
  235. package/dist/providers/github.d.ts +1 -1
  236. package/dist/providers/github.d.ts.map +1 -1
  237. package/dist/providers/github.js +9 -4
  238. package/dist/providers/github.js.map +1 -1
  239. package/dist/providers/google.d.ts +1 -1
  240. package/dist/providers/google.d.ts.map +1 -1
  241. package/dist/providers/google.js +9 -4
  242. package/dist/providers/google.js.map +1 -1
  243. package/dist/providers/microsoft.d.ts +1 -1
  244. package/dist/providers/microsoft.d.ts.map +1 -1
  245. package/dist/providers/microsoft.js +12 -4
  246. package/dist/providers/microsoft.js.map +1 -1
  247. package/dist/providers/password.d.ts +117 -15
  248. package/dist/providers/password.d.ts.map +1 -1
  249. package/dist/providers/password.js +71 -26
  250. package/dist/providers/password.js.map +1 -1
  251. package/dist/providers/phone.d.ts +4 -3
  252. package/dist/providers/phone.d.ts.map +1 -1
  253. package/dist/providers/phone.js.map +1 -1
  254. package/dist/providers/webauthn.d.ts.map +1 -1
  255. package/dist/providers/webauthn.js +6 -0
  256. package/dist/providers/webauthn.js.map +1 -1
  257. package/dist/react/index.d.ts +40 -41
  258. package/dist/react/index.d.ts.map +1 -1
  259. package/dist/react/index.js +27 -52
  260. package/dist/react/index.js.map +1 -1
  261. package/dist/server/auth.d.ts +224 -126
  262. package/dist/server/auth.d.ts.map +1 -1
  263. package/dist/server/auth.js +44 -25
  264. package/dist/server/auth.js.map +1 -1
  265. package/dist/server/component/factor/db.js +13 -6
  266. package/dist/server/component/factor/db.js.map +1 -1
  267. package/dist/server/config.d.ts +2 -1
  268. package/dist/server/connection/domain.d.ts +4 -65
  269. package/dist/server/connection/domain.d.ts.map +1 -1
  270. package/dist/server/connection/domain.js +29 -5
  271. package/dist/server/connection/domain.js.map +1 -1
  272. package/dist/server/connection/group/service.js +7 -5
  273. package/dist/server/connection/group/service.js.map +1 -1
  274. package/dist/server/connection/http.js +136 -291
  275. package/dist/server/connection/http.js.map +1 -1
  276. package/dist/server/connection/oidc.js +8 -17
  277. package/dist/server/connection/oidc.js.map +1 -1
  278. package/dist/server/connection/policy/domain.js +4 -1
  279. package/dist/server/connection/policy/domain.js.map +1 -1
  280. package/dist/server/connection/policy.js +14 -13
  281. package/dist/server/connection/policy.js.map +1 -1
  282. package/dist/server/connection/provision.js +5 -19
  283. package/dist/server/connection/provision.js.map +1 -1
  284. package/dist/server/connection/saml/encoding.js +2 -6
  285. package/dist/server/connection/saml/encoding.js.map +1 -1
  286. package/dist/server/connection/saml/signature.js +2 -2
  287. package/dist/server/connection/saml/signature.js.map +1 -1
  288. package/dist/server/connection/saml/xmldsig.js +1 -1
  289. package/dist/server/connection/saml/xmldsig.js.map +1 -1
  290. package/dist/server/connection/webhook.js +4 -36
  291. package/dist/server/connection/webhook.js.map +1 -1
  292. package/dist/server/context.d.ts +2 -2
  293. package/dist/server/context.d.ts.map +1 -1
  294. package/dist/server/context.js +35 -24
  295. package/dist/server/context.js.map +1 -1
  296. package/dist/server/contract.d.ts.map +1 -1
  297. package/dist/server/contract.js +6 -14
  298. package/dist/server/contract.js.map +1 -1
  299. package/dist/server/core.js +46 -1
  300. package/dist/server/core.js.map +1 -1
  301. package/dist/server/cors.d.ts +2 -2
  302. package/dist/server/cors.d.ts.map +1 -1
  303. package/dist/server/crypto.js.map +1 -1
  304. package/dist/server/db.js +6 -2
  305. package/dist/server/db.js.map +1 -1
  306. package/dist/server/device.js +1 -1
  307. package/dist/server/domains/account.d.ts +9 -1
  308. package/dist/server/domains/account.d.ts.map +1 -1
  309. package/dist/server/domains/account.js +21 -9
  310. package/dist/server/domains/account.js.map +1 -1
  311. package/dist/server/domains/context.js +34 -0
  312. package/dist/server/domains/context.js.map +1 -0
  313. package/dist/server/domains/factor.d.ts +3 -2
  314. package/dist/server/domains/factor.d.ts.map +1 -1
  315. package/dist/server/domains/factor.js.map +1 -1
  316. package/dist/server/domains/group.js.map +1 -1
  317. package/dist/server/domains/invite.js.map +1 -1
  318. package/dist/server/domains/key.js.map +1 -1
  319. package/dist/server/domains/member.js.map +1 -1
  320. package/dist/server/domains/session.js.map +1 -1
  321. package/dist/server/domains/user.js.map +1 -1
  322. package/dist/server/env.js +2 -22
  323. package/dist/server/env.js.map +1 -1
  324. package/dist/server/events.d.ts +3 -1
  325. package/dist/server/events.d.ts.map +1 -1
  326. package/dist/server/events.js +6 -6
  327. package/dist/server/events.js.map +1 -1
  328. package/dist/server/facade.d.ts +1 -33
  329. package/dist/server/facade.d.ts.map +1 -1
  330. package/dist/server/facade.js +1 -2
  331. package/dist/server/facade.js.map +1 -1
  332. package/dist/server/http.d.ts +1 -0
  333. package/dist/server/http.d.ts.map +1 -1
  334. package/dist/server/http.js +4 -4
  335. package/dist/server/http.js.map +1 -1
  336. package/dist/server/identity/claims.js +1 -1
  337. package/dist/server/identity/convex.d.ts +2 -0
  338. package/dist/server/identity/convex.d.ts.map +1 -1
  339. package/dist/server/index.d.ts +6 -9
  340. package/dist/server/index.js +2 -4
  341. package/dist/server/limits.js +23 -2
  342. package/dist/server/limits.js.map +1 -1
  343. package/dist/server/mutations/calls.js +3 -2
  344. package/dist/server/mutations/credentials/signin.js +7 -3
  345. package/dist/server/mutations/credentials/signin.js.map +1 -1
  346. package/dist/server/mutations/enrollment.js +87 -0
  347. package/dist/server/mutations/enrollment.js.map +1 -0
  348. package/dist/server/mutations/invalidate.js +5 -10
  349. package/dist/server/mutations/invalidate.js.map +1 -1
  350. package/dist/server/mutations/oauth.js +3 -3
  351. package/dist/server/mutations/oauth.js.map +1 -1
  352. package/dist/server/mutations/refresh.js +1 -0
  353. package/dist/server/mutations/refresh.js.map +1 -1
  354. package/dist/server/mutations/register.js +52 -21
  355. package/dist/server/mutations/register.js.map +1 -1
  356. package/dist/server/mutations/retrieve.js +4 -1
  357. package/dist/server/mutations/retrieve.js.map +1 -1
  358. package/dist/server/mutations/signin.js +2 -2
  359. package/dist/server/mutations/signin.js.map +1 -1
  360. package/dist/server/mutations/store.js +6 -1
  361. package/dist/server/mutations/store.js.map +1 -1
  362. package/dist/server/mutations/verify.js +6 -4
  363. package/dist/server/mutations/verify.js.map +1 -1
  364. package/dist/server/oauth/client.d.ts +1 -1
  365. package/dist/server/oauth/client.js.map +1 -1
  366. package/dist/server/oauth/code.d.ts +1 -1
  367. package/dist/server/oauth/code.js.map +1 -1
  368. package/dist/server/oauth/factory.js +89 -13
  369. package/dist/server/oauth/factory.js.map +1 -1
  370. package/dist/server/oauth/handlers.js +2 -2
  371. package/dist/server/oauth/runtime.js +24 -9
  372. package/dist/server/oauth/runtime.js.map +1 -1
  373. package/dist/server/preload.d.ts.map +1 -1
  374. package/dist/server/preload.js +14 -11
  375. package/dist/server/preload.js.map +1 -1
  376. package/dist/server/runtime.d.ts +236 -148
  377. package/dist/server/runtime.d.ts.map +1 -1
  378. package/dist/server/runtime.js +92 -44
  379. package/dist/server/runtime.js.map +1 -1
  380. package/dist/server/session/lifecycle.d.ts +2 -1
  381. package/dist/server/session/lifecycle.d.ts.map +1 -1
  382. package/dist/server/session/lifecycle.js +29 -10
  383. package/dist/server/session/lifecycle.js.map +1 -1
  384. package/dist/server/signin/flow.js +2 -2
  385. package/dist/server/signin/flow.js.map +1 -1
  386. package/dist/server/telemetry.js +1 -1
  387. package/dist/server/tokens.js +6 -3
  388. package/dist/server/tokens.js.map +1 -1
  389. package/dist/server/totp.js +4 -3
  390. package/dist/server/totp.js.map +1 -1
  391. package/dist/server/types.d.ts +131 -45
  392. package/dist/server/types.d.ts.map +1 -1
  393. package/dist/server/user/account.js +0 -1
  394. package/dist/server/user/account.js.map +1 -1
  395. package/dist/server/validators.d.ts +930 -944
  396. package/dist/server/validators.d.ts.map +1 -1
  397. package/dist/server/validators.js +66 -39
  398. package/dist/server/validators.js.map +1 -1
  399. package/dist/server/webauthn.js +60 -29
  400. package/dist/server/webauthn.js.map +1 -1
  401. package/dist/shared/brand.d.ts +3 -7
  402. package/dist/shared/brand.d.ts.map +1 -1
  403. package/dist/shared/params.d.ts +78 -0
  404. package/dist/shared/params.d.ts.map +1 -0
  405. package/dist/shared/results.d.ts +13 -1
  406. package/dist/shared/results.d.ts.map +1 -1
  407. package/dist/svelte/context.svelte.d.ts +23 -12
  408. package/dist/svelte/context.svelte.d.ts.map +1 -1
  409. package/dist/svelte/context.svelte.js +20 -13
  410. package/dist/svelte/index.d.ts +1 -4
  411. package/dist/svelte/index.d.ts.map +1 -1
  412. package/dist/svelte/index.js +1 -4
  413. package/dist/test.d.ts +1204 -611
  414. package/dist/test.d.ts.map +1 -1
  415. package/dist/test.js +50 -1
  416. package/dist/test.js.map +1 -1
  417. package/package.json +5 -14
  418. package/dist/_generated/component.d.ts +0 -3074
  419. package/dist/_generated/component.d.ts.map +0 -1
  420. package/dist/component/functions.d.ts +0 -9
  421. package/dist/component/functions.d.ts.map +0 -1
  422. package/dist/component/functions.js +0 -3
  423. package/dist/core/index.d.ts +0 -533
  424. package/dist/core/index.d.ts.map +0 -1
  425. package/dist/core/index.js +0 -86
  426. package/dist/core/index.js.map +0 -1
  427. package/dist/model.js.map +0 -1
  428. package/dist/server/env.d.ts +0 -28
  429. package/dist/server/env.d.ts.map +0 -1
  430. package/dist/svelte/AuthLoading.svelte +0 -13
  431. package/dist/svelte/AuthLoading.svelte.d.ts +0 -8
  432. package/dist/svelte/AuthLoading.svelte.d.ts.map +0 -1
  433. package/dist/svelte/SignedIn.svelte +0 -14
  434. package/dist/svelte/SignedIn.svelte.d.ts +0 -8
  435. package/dist/svelte/SignedIn.svelte.d.ts.map +0 -1
  436. package/dist/svelte/SignedOut.svelte +0 -13
  437. package/dist/svelte/SignedOut.svelte.d.ts +0 -8
  438. package/dist/svelte/SignedOut.svelte.d.ts.map +0 -1
@@ -1,8 +1,10 @@
1
1
  import { ErrorCode } from "../../../shared/codes.js";
2
- import { vGroupConnectionScimIdentityDoc, vPaginated, vScimResourceType } from "../../model.js";
2
+ import { vPaginated, vScimResourceType } from "../../model.js";
3
3
  import schema_default from "../../schema.js";
4
4
  import { mutation, query } from "../../_generated/server.js";
5
- import "../../functions.js";
5
+ import { vGroupConnectionScimIdentityDoc } from "../../documents.js";
6
+ import { revokeSessionState } from "../../session.js";
7
+ import { assertBatchSelectorSize } from "../../batch.js";
6
8
  import { ConvexError, v } from "convex/values";
7
9
  import { paginationOptsValidator } from "convex/server";
8
10
  import { paginator } from "convex-helpers/server/pagination";
@@ -17,11 +19,24 @@ import { paginator } from "convex-helpers/server/pagination";
17
19
  *
18
20
  * @module
19
21
  */
20
- const vScimUserData = v.object(schema_default.tables.User.validator.fields);
22
+ const vScimUserData = schema_default.tables.User.validator.omit("sessionEpoch");
23
+ const vProfileUpdate = v.union(v.literal("never"), v.literal("missing"), v.literal("always"));
24
+ /** Maximum memberships changed by one SCIM group mutation. */
25
+ const SCIM_GROUP_MEMBERSHIP_BATCH_SIZE = 100;
26
+ const vScimMembershipProgress = v.object({
27
+ isDone: v.boolean(),
28
+ continueCursor: v.string()
29
+ });
30
+ function assertScimMembershipBatchSize(memberIds) {
31
+ if (memberIds.length > SCIM_GROUP_MEMBERSHIP_BATCH_SIZE) throw new ConvexError({
32
+ code: ErrorCode.INVALID_PARAMETERS,
33
+ message: `SCIM group membership batches are limited to ${SCIM_GROUP_MEMBERSHIP_BATCH_SIZE} members.`
34
+ });
35
+ }
21
36
  /**
22
37
  * Read SCIM identities, overloaded by the args supplied. With
23
38
  * `{ connectionId, userIds }` it batch-resolves and returns an array aligned to
24
- * the input order (`null` per missing user). Otherwise it resolves a single
39
+ * the input order (`null` per missing user; max 100 IDs). Otherwise it resolves a single
25
40
  * identity by `(connectionId, resourceType, externalId)`, `(connectionId,
26
41
  * userId)`, `userId`, or `mappedGroupId`. Returns `null` when nothing matches.
27
42
  */
@@ -38,6 +53,7 @@ const get = query({
38
53
  handler: async (ctx, args) => {
39
54
  if (args.connectionId !== void 0 && args.userIds !== void 0) {
40
55
  const userIds = args.userIds;
56
+ assertBatchSelectorSize(userIds, "userIds");
41
57
  if (userIds.length === 0) return [];
42
58
  const unique = Array.from(new Set(userIds));
43
59
  const docs = await Promise.all(unique.map((userId) => ctx.db.query("GroupConnectionScimIdentity").withIndex("group_connection_id_user_id", (idx) => idx.eq("connectionId", args.connectionId).eq("userId", userId)).first()));
@@ -62,43 +78,29 @@ const list = query({
62
78
  return await paginator(ctx.db, schema_default).query("GroupConnectionScimIdentity").withIndex("group_connection_id", (idx) => idx.eq("connectionId", connectionId)).paginate(paginationOpts);
63
79
  }
64
80
  });
65
- /** Insert a SCIM identity, or patch it when it already exists (keyed by `(connectionId, resourceType, externalId)`). */
66
- const upsert = mutation({
67
- args: {
68
- connectionId: v.id("GroupConnection"),
69
- groupId: v.id("Group"),
70
- resourceType: vScimResourceType,
71
- externalId: v.string(),
72
- userId: v.optional(v.id("User")),
73
- mappedGroupId: v.optional(v.id("Group")),
74
- lastProvisionedAt: v.optional(v.number()),
75
- active: v.optional(v.boolean()),
76
- raw: v.optional(v.any())
77
- },
78
- returns: v.id("GroupConnectionScimIdentity"),
79
- handler: async (ctx, args) => {
80
- const existing = await ctx.db.query("GroupConnectionScimIdentity").withIndex("group_connection_id_resource_type_external_id", (idx) => idx.eq("connectionId", args.connectionId).eq("resourceType", args.resourceType).eq("externalId", args.externalId)).first();
81
- if (existing) {
82
- await ctx.db.patch("GroupConnectionScimIdentity", existing._id, args);
83
- return existing._id;
84
- }
85
- return await ctx.db.insert("GroupConnectionScimIdentity", args);
86
- }
87
- });
81
+ function providerForConnection(connection) {
82
+ if (connection.protocol === "oidc") return `oidc:${connection._id}`;
83
+ if (connection.protocol === "saml") return `saml:${connection._id}`;
84
+ throw new ConvexError({
85
+ code: ErrorCode.PROVIDER_NOT_CONFIGURED,
86
+ message: "SCIM requires an OIDC or SAML connection."
87
+ });
88
+ }
89
+ function patchProfile(current, next, mode) {
90
+ if (mode === "never") return {};
91
+ return Object.fromEntries(Object.entries(next).filter(([key, value]) => value === void 0 ? false : mode === "always" || current[key] === void 0 || current[key] === null || current[key] === ""));
92
+ }
88
93
  /**
89
- * Atomically provision or resolve a SCIM user by both of its durable natural
90
- * keys: the connection-scoped SCIM external id and the provider Account id.
91
- * A concurrent retry cannot commit a losing User because the identity and
92
- * Account index reads participate in the same OCC transaction as the inserts.
93
- * Existing ownership is preserved; conflicting owners are rejected.
94
+ * Atomically provision a directory-managed user, account, SCIM identity, and
95
+ * membership. Group and provider ownership are derived from the connection.
94
96
  */
95
97
  const provision = mutation({
96
98
  args: {
97
99
  connectionId: v.id("GroupConnection"),
98
- groupId: v.id("Group"),
99
- externalId: v.string(),
100
- provider: v.string(),
100
+ externalId: v.optional(v.string()),
101
101
  userData: vScimUserData,
102
+ profileUpdate: vProfileUpdate,
103
+ roleIds: v.array(v.string()),
102
104
  lastProvisionedAt: v.optional(v.number()),
103
105
  active: v.optional(v.boolean()),
104
106
  raw: v.optional(v.any())
@@ -108,56 +110,402 @@ const provision = mutation({
108
110
  created: v.boolean()
109
111
  }),
110
112
  handler: async (ctx, args) => {
111
- const identity = await ctx.db.query("GroupConnectionScimIdentity").withIndex("group_connection_id_resource_type_external_id", (idx) => idx.eq("connectionId", args.connectionId).eq("resourceType", "user").eq("externalId", args.externalId)).unique();
112
- const account = await ctx.db.query("Account").withIndex("provider_account_id", (idx) => idx.eq("provider", args.provider).eq("providerAccountId", args.externalId)).unique();
113
+ const connection = await activeScimConnection(ctx, args.connectionId);
114
+ const provider = providerForConnection(connection);
115
+ const externalId = args.externalId;
116
+ const identity = externalId === void 0 ? null : await ctx.db.query("GroupConnectionScimIdentity").withIndex("group_connection_id_resource_type_external_id", (idx) => idx.eq("connectionId", args.connectionId).eq("resourceType", "user").eq("externalId", externalId)).unique();
117
+ const account = externalId === void 0 ? null : await ctx.db.query("Account").withIndex("provider_account_id", (idx) => idx.eq("provider", provider).eq("providerAccountId", externalId)).unique();
113
118
  if (identity?.userId !== void 0 && account !== null && identity.userId !== account.userId) throw new ConvexError({
114
119
  code: ErrorCode.ACCOUNT_ALREADY_LINKED,
115
- message: "The SCIM identity and provider account belong to different users."
120
+ message: "SCIM account ownership conflicts."
116
121
  });
117
122
  let userId = identity?.userId ?? account?.userId;
118
123
  let created = false;
119
- if (userId !== void 0) {
120
- if (await ctx.db.get("User", userId) === null) throw new ConvexError({
121
- code: ErrorCode.ACCOUNT_NOT_FOUND,
122
- message: "The SCIM identity references a user that no longer exists."
124
+ if (userId === void 0) {
125
+ userId = await ctx.db.insert("User", {
126
+ ...args.userData,
127
+ sessionEpoch: 0
123
128
  });
124
- } else {
125
- userId = await ctx.db.insert("User", args.userData);
126
129
  created = true;
130
+ } else {
131
+ const user = await ctx.db.get("User", userId);
132
+ if (user === null) throw new ConvexError({
133
+ code: ErrorCode.ACCOUNT_NOT_FOUND,
134
+ message: "SCIM user not found."
135
+ });
136
+ if (await ctx.db.query("GroupConnectionScimIdentity").withIndex("user_id", (idx) => idx.eq("userId", userId)).filter((query$1) => query$1.neq(query$1.field("connectionId"), args.connectionId)).first() !== null) throw new ConvexError({
137
+ code: ErrorCode.ACCOUNT_ALREADY_LINKED,
138
+ message: "User is managed by another SCIM connection."
139
+ });
140
+ const patch = patchProfile(user, args.userData, args.profileUpdate);
141
+ if (Object.keys(patch).length > 0) await ctx.db.patch("User", userId, patch);
127
142
  }
128
- if (account === null) await ctx.db.insert("Account", {
143
+ if (externalId !== void 0 && account === null) await ctx.db.insert("Account", {
129
144
  userId,
130
- provider: args.provider,
131
- providerAccountId: args.externalId
145
+ provider,
146
+ providerAccountId: externalId
132
147
  });
133
148
  const identityData = {
134
149
  connectionId: args.connectionId,
135
- groupId: args.groupId,
150
+ groupId: connection.groupId,
136
151
  resourceType: "user",
137
- externalId: args.externalId,
138
- userId
152
+ ...externalId === void 0 ? {} : { externalId },
153
+ userId,
154
+ active: args.active !== false,
155
+ ...args.lastProvisionedAt === void 0 ? {} : { lastProvisionedAt: args.lastProvisionedAt },
156
+ ...args.raw === void 0 ? {} : { raw: args.raw }
139
157
  };
140
- if (args.lastProvisionedAt !== void 0) identityData.lastProvisionedAt = args.lastProvisionedAt;
141
- if (args.active !== void 0) identityData.active = args.active;
142
- if (args.raw !== void 0) identityData.raw = args.raw;
143
158
  if (identity === null) await ctx.db.insert("GroupConnectionScimIdentity", identityData);
144
- else await ctx.db.patch("GroupConnectionScimIdentity", identity._id, identityData);
159
+ else {
160
+ if (identity.groupId !== connection.groupId) throw new ConvexError({
161
+ code: ErrorCode.INVALID_PARAMETERS,
162
+ message: "SCIM identity group mismatch."
163
+ });
164
+ await ctx.db.patch("GroupConnectionScimIdentity", identity._id, identityData);
165
+ }
166
+ const membership = await ctx.db.query("GroupMember").withIndex("group_id_user_id", (idx) => idx.eq("groupId", connection.groupId).eq("userId", userId)).unique();
167
+ const membershipPatch = {
168
+ roleIds: args.roleIds,
169
+ status: args.active === false ? "inactive" : "active"
170
+ };
171
+ if (membership === null) await ctx.db.insert("GroupMember", {
172
+ groupId: connection.groupId,
173
+ userId,
174
+ ...membershipPatch
175
+ });
176
+ else await ctx.db.patch("GroupMember", membership._id, membershipPatch);
145
177
  return {
146
178
  userId,
147
179
  created
148
180
  };
149
181
  }
150
182
  });
151
- /** Delete a SCIM identity by id. */
152
- const remove = mutation({
153
- args: { id: v.id("GroupConnectionScimIdentity") },
183
+ /** Atomically update a directory-managed user and its connection membership. */
184
+ const update = mutation({
185
+ args: {
186
+ connectionId: v.id("GroupConnection"),
187
+ userId: v.id("User"),
188
+ externalId: v.optional(v.string()),
189
+ userData: vScimUserData,
190
+ profileUpdate: vProfileUpdate,
191
+ roleIds: v.array(v.string()),
192
+ active: v.boolean(),
193
+ lastProvisionedAt: v.optional(v.number()),
194
+ raw: v.optional(v.any())
195
+ },
154
196
  returns: v.null(),
155
- handler: async (ctx, { id: identityId }) => {
156
- await ctx.db.delete("GroupConnectionScimIdentity", identityId);
197
+ handler: async (ctx, args) => {
198
+ const connection = await activeScimConnection(ctx, args.connectionId);
199
+ const externalId = args.externalId;
200
+ const identity = await ctx.db.query("GroupConnectionScimIdentity").withIndex("group_connection_id_user_id", (idx) => idx.eq("connectionId", args.connectionId).eq("userId", args.userId)).unique();
201
+ if (identity === null || identity.resourceType !== "user" || identity.groupId !== connection.groupId) throw new ConvexError({
202
+ code: ErrorCode.ACCOUNT_NOT_FOUND,
203
+ message: "SCIM user not found."
204
+ });
205
+ if (await ctx.db.query("GroupConnectionScimIdentity").withIndex("user_id", (idx) => idx.eq("userId", args.userId)).filter((query$1) => query$1.neq(query$1.field("connectionId"), args.connectionId)).first() !== null) throw new ConvexError({
206
+ code: ErrorCode.ACCOUNT_ALREADY_LINKED,
207
+ message: "User is managed by another SCIM connection."
208
+ });
209
+ const conflicting = externalId === void 0 ? null : await ctx.db.query("GroupConnectionScimIdentity").withIndex("group_connection_id_resource_type_external_id", (idx) => idx.eq("connectionId", args.connectionId).eq("resourceType", "user").eq("externalId", externalId)).unique();
210
+ if (conflicting !== null && conflicting._id !== identity._id) throw new ConvexError({
211
+ code: ErrorCode.ACCOUNT_ALREADY_LINKED,
212
+ message: "SCIM external id is already linked."
213
+ });
214
+ const user = await ctx.db.get("User", args.userId);
215
+ if (user === null) throw new ConvexError({
216
+ code: ErrorCode.ACCOUNT_NOT_FOUND,
217
+ message: "User not found."
218
+ });
219
+ const provider = providerForConnection(connection);
220
+ const currentExternalId = identity.externalId;
221
+ const [currentAccount, nextAccount] = await Promise.all([currentExternalId === void 0 ? Promise.resolve(null) : ctx.db.query("Account").withIndex("provider_account_id", (idx) => idx.eq("provider", provider).eq("providerAccountId", currentExternalId)).unique(), externalId === void 0 || currentExternalId === externalId ? Promise.resolve(null) : ctx.db.query("Account").withIndex("provider_account_id", (idx) => idx.eq("provider", provider).eq("providerAccountId", externalId)).unique()]);
222
+ if (nextAccount !== null && nextAccount.userId !== args.userId) throw new ConvexError({
223
+ code: ErrorCode.ACCOUNT_ALREADY_LINKED,
224
+ message: "The replacement SCIM external id is already linked."
225
+ });
226
+ if (currentAccount !== null && currentAccount.userId !== args.userId) throw new ConvexError({
227
+ code: ErrorCode.ACCOUNT_ALREADY_LINKED,
228
+ message: "The SCIM account belongs to another user."
229
+ });
230
+ const patch = patchProfile(user, args.userData, args.profileUpdate);
231
+ if (Object.keys(patch).length > 0) await ctx.db.patch("User", args.userId, patch);
232
+ if (currentExternalId === externalId) {
233
+ if (externalId !== void 0 && currentAccount === null) await ctx.db.insert("Account", {
234
+ userId: args.userId,
235
+ provider,
236
+ providerAccountId: externalId
237
+ });
238
+ } else if (currentAccount !== null) if (externalId === void 0) await ctx.db.delete("Account", currentAccount._id);
239
+ else if (nextAccount === null) await ctx.db.patch("Account", currentAccount._id, { providerAccountId: externalId });
240
+ else await ctx.db.delete("Account", currentAccount._id);
241
+ else if (externalId !== void 0 && nextAccount === null) await ctx.db.insert("Account", {
242
+ userId: args.userId,
243
+ provider,
244
+ providerAccountId: externalId
245
+ });
246
+ await ctx.db.patch("GroupConnectionScimIdentity", identity._id, {
247
+ externalId,
248
+ active: args.active,
249
+ lastProvisionedAt: args.lastProvisionedAt,
250
+ raw: args.raw
251
+ });
252
+ const membership = await ctx.db.query("GroupMember").withIndex("group_id_user_id", (idx) => idx.eq("groupId", connection.groupId).eq("userId", args.userId)).unique();
253
+ const membershipPatch = {
254
+ roleIds: args.roleIds,
255
+ status: args.active ? "active" : "inactive"
256
+ };
257
+ if (membership === null) await ctx.db.insert("GroupMember", {
258
+ groupId: connection.groupId,
259
+ userId: args.userId,
260
+ ...membershipPatch
261
+ });
262
+ else await ctx.db.patch("GroupMember", membership._id, membershipPatch);
157
263
  return null;
158
264
  }
159
265
  });
266
+ /** Atomically revoke a directory-managed user's membership, sessions, and identity. */
267
+ const revoke = mutation({
268
+ args: {
269
+ connectionId: v.id("GroupConnection"),
270
+ userId: v.id("User"),
271
+ mode: v.union(v.literal("soft"), v.literal("hard"))
272
+ },
273
+ returns: v.object({
274
+ epoch: v.number(),
275
+ cleanedSessions: v.number(),
276
+ cleanupPending: v.boolean()
277
+ }),
278
+ handler: async (ctx, args) => {
279
+ const connection = await activeScimConnection(ctx, args.connectionId);
280
+ const identity = await ctx.db.query("GroupConnectionScimIdentity").withIndex("group_connection_id_user_id", (idx) => idx.eq("connectionId", args.connectionId).eq("userId", args.userId)).unique();
281
+ if (identity === null || identity.resourceType !== "user" || identity.groupId !== connection.groupId) throw new ConvexError({
282
+ code: ErrorCode.ACCOUNT_NOT_FOUND,
283
+ message: "SCIM user not found."
284
+ });
285
+ if (await ctx.db.query("GroupConnectionScimIdentity").withIndex("user_id", (idx) => idx.eq("userId", args.userId)).filter((query$1) => query$1.neq(query$1.field("connectionId"), args.connectionId)).first() !== null) throw new ConvexError({
286
+ code: ErrorCode.ACCOUNT_ALREADY_LINKED,
287
+ message: "User is managed by another SCIM connection."
288
+ });
289
+ const provider = providerForConnection(connection);
290
+ const externalId = identity.externalId;
291
+ const account = externalId === void 0 ? null : await ctx.db.query("Account").withIndex("provider_account_id", (idx) => idx.eq("provider", provider).eq("providerAccountId", externalId)).unique();
292
+ if (account !== null && account.userId !== args.userId) throw new ConvexError({
293
+ code: ErrorCode.ACCOUNT_ALREADY_LINKED,
294
+ message: "The SCIM account belongs to another user."
295
+ });
296
+ const membership = await ctx.db.query("GroupMember").withIndex("group_id_user_id", (idx) => idx.eq("groupId", connection.groupId).eq("userId", args.userId)).unique();
297
+ if (membership !== null) await ctx.db.delete("GroupMember", membership._id);
298
+ if (account !== null) await ctx.db.delete("Account", account._id);
299
+ const { epoch, cleanedSessions, cleanupPending } = await revokeSessionState(ctx, args.userId);
300
+ if (args.mode === "hard") await ctx.db.delete("GroupConnectionScimIdentity", identity._id);
301
+ else await ctx.db.patch("GroupConnectionScimIdentity", identity._id, {
302
+ active: false,
303
+ lastProvisionedAt: Date.now()
304
+ });
305
+ return {
306
+ epoch,
307
+ cleanedSessions,
308
+ cleanupPending
309
+ };
310
+ }
311
+ });
312
+ async function activeScimConnection(ctx, connectionId) {
313
+ const connection = await ctx.db.get("GroupConnection", connectionId);
314
+ const scim = connection === null ? null : await ctx.db.query("GroupConnectionScimConfig").withIndex("group_connection_id", (idx) => idx.eq("connectionId", connectionId)).unique();
315
+ if (connection === null || connection.status !== "active" || scim === null || scim.status !== "active" || scim.groupId !== connection.groupId) throw new ConvexError({
316
+ code: ErrorCode.INVALID_PARAMETERS,
317
+ message: "SCIM connection is not active."
318
+ });
319
+ return connection;
320
+ }
321
+ async function assertScimMembers(ctx, connection, userIds) {
322
+ for (const userId of new Set(userIds)) {
323
+ const [user, identity, membership] = await Promise.all([
324
+ ctx.db.get("User", userId),
325
+ ctx.db.query("GroupConnectionScimIdentity").withIndex("group_connection_id_user_id", (idx) => idx.eq("connectionId", connection._id).eq("userId", userId)).first(),
326
+ ctx.db.query("GroupMember").withIndex("group_id_user_id", (idx) => idx.eq("groupId", connection.groupId).eq("userId", userId)).first()
327
+ ]);
328
+ if (user === null || identity === null && membership === null) throw new ConvexError({
329
+ code: ErrorCode.ACCOUNT_NOT_FOUND,
330
+ message: "A SCIM group member is not available through this connection."
331
+ });
332
+ }
333
+ }
334
+ async function replaceScimGroupMembers(ctx, groupId, memberIds, roleIds, cursor) {
335
+ assertScimMembershipBatchSize(memberIds);
336
+ const wanted = new Set(memberIds);
337
+ const patch = {
338
+ roleIds,
339
+ status: "active"
340
+ };
341
+ for (const userId of wanted) {
342
+ const member = await ctx.db.query("GroupMember").withIndex("group_id_user_id", (idx) => idx.eq("groupId", groupId).eq("userId", userId)).unique();
343
+ if (member === null) await ctx.db.insert("GroupMember", {
344
+ groupId,
345
+ userId,
346
+ ...patch
347
+ });
348
+ else await ctx.db.patch("GroupMember", member._id, patch);
349
+ }
350
+ const current = await paginator(ctx.db, schema_default).query("GroupMember").withIndex("group_id", (idx) => idx.eq("groupId", groupId)).paginate({
351
+ numItems: SCIM_GROUP_MEMBERSHIP_BATCH_SIZE,
352
+ cursor: cursor ?? null
353
+ });
354
+ for (const member of current.page) if (!wanted.has(member.userId)) await ctx.db.delete("GroupMember", member._id);
355
+ return {
356
+ isDone: current.isDone,
357
+ continueCursor: current.continueCursor
358
+ };
359
+ }
360
+ /**
361
+ * Provision a SCIM group and one bounded page of its authoritative membership.
362
+ * Repeat with `continueCursor` until `isDone` is true.
363
+ */
364
+ const provisionGroup = mutation({
365
+ args: {
366
+ connectionId: v.id("GroupConnection"),
367
+ externalId: v.optional(v.string()),
368
+ name: v.string(),
369
+ memberIds: v.array(v.id("User")),
370
+ roleIds: v.array(v.string()),
371
+ raw: v.optional(v.any()),
372
+ cursor: v.optional(v.string())
373
+ },
374
+ returns: v.object({
375
+ groupId: v.id("Group"),
376
+ created: v.boolean(),
377
+ ...vScimMembershipProgress.fields
378
+ }),
379
+ handler: async (ctx, args) => {
380
+ const connection = await activeScimConnection(ctx, args.connectionId);
381
+ const externalId = args.externalId;
382
+ assertScimMembershipBatchSize(args.memberIds);
383
+ await assertScimMembers(ctx, connection, args.memberIds);
384
+ const identity = externalId === void 0 ? null : await ctx.db.query("GroupConnectionScimIdentity").withIndex("group_connection_id_resource_type_external_id", (idx) => idx.eq("connectionId", args.connectionId).eq("resourceType", "group").eq("externalId", externalId)).unique();
385
+ if (identity !== null && identity.groupId !== connection.groupId) throw new ConvexError({
386
+ code: ErrorCode.INVALID_PARAMETERS,
387
+ message: "SCIM identity group mismatch."
388
+ });
389
+ let groupId = identity?.mappedGroupId;
390
+ let created = false;
391
+ if (groupId === void 0) {
392
+ const parent = await ctx.db.get("Group", connection.groupId);
393
+ if (parent === null) throw new ConvexError({
394
+ code: ErrorCode.INVALID_PARAMETERS,
395
+ message: "Connection group not found."
396
+ });
397
+ groupId = await ctx.db.insert("Group", {
398
+ name: args.name,
399
+ type: "organization",
400
+ parentGroupId: connection.groupId,
401
+ rootGroupId: parent.rootGroupId ?? parent._id,
402
+ isRoot: false
403
+ });
404
+ created = true;
405
+ } else {
406
+ const group = await ctx.db.get("Group", groupId);
407
+ if (group === null || group.parentGroupId !== connection.groupId) throw new ConvexError({
408
+ code: ErrorCode.INVALID_PARAMETERS,
409
+ message: "SCIM group ownership mismatch."
410
+ });
411
+ await ctx.db.patch("Group", groupId, { name: args.name });
412
+ }
413
+ const identityData = {
414
+ connectionId: args.connectionId,
415
+ groupId: connection.groupId,
416
+ resourceType: "group",
417
+ ...externalId === void 0 ? {} : { externalId },
418
+ mappedGroupId: groupId,
419
+ active: true,
420
+ lastProvisionedAt: Date.now(),
421
+ ...args.raw === void 0 ? {} : { raw: args.raw }
422
+ };
423
+ if (identity === null) await ctx.db.insert("GroupConnectionScimIdentity", identityData);
424
+ else await ctx.db.patch("GroupConnectionScimIdentity", identity._id, identityData);
425
+ return {
426
+ groupId,
427
+ created,
428
+ ...await replaceScimGroupMembers(ctx, groupId, args.memberIds, args.roleIds, args.cursor)
429
+ };
430
+ }
431
+ });
432
+ /**
433
+ * Update a SCIM group and one bounded page of its authoritative membership.
434
+ * Repeat with `continueCursor` until `isDone` is true.
435
+ */
436
+ const updateGroup = mutation({
437
+ args: {
438
+ connectionId: v.id("GroupConnection"),
439
+ groupId: v.id("Group"),
440
+ name: v.optional(v.string()),
441
+ memberIds: v.array(v.id("User")),
442
+ roleIds: v.array(v.string()),
443
+ raw: v.optional(v.any()),
444
+ cursor: v.optional(v.string())
445
+ },
446
+ returns: vScimMembershipProgress,
447
+ handler: async (ctx, args) => {
448
+ const connection = await activeScimConnection(ctx, args.connectionId);
449
+ assertScimMembershipBatchSize(args.memberIds);
450
+ const identity = await ctx.db.query("GroupConnectionScimIdentity").withIndex("mapped_group_id", (idx) => idx.eq("mappedGroupId", args.groupId)).unique();
451
+ if (identity === null || identity.connectionId !== args.connectionId || identity.groupId !== connection.groupId || identity.resourceType !== "group") throw new ConvexError({
452
+ code: ErrorCode.ACCOUNT_NOT_FOUND,
453
+ message: "SCIM group not found."
454
+ });
455
+ const group = await ctx.db.get("Group", args.groupId);
456
+ if (group === null || group.parentGroupId !== connection.groupId) throw new ConvexError({
457
+ code: ErrorCode.INVALID_PARAMETERS,
458
+ message: "SCIM group ownership mismatch."
459
+ });
460
+ await assertScimMembers(ctx, connection, args.memberIds);
461
+ if (args.name !== void 0) await ctx.db.patch("Group", args.groupId, { name: args.name });
462
+ await ctx.db.patch("GroupConnectionScimIdentity", identity._id, {
463
+ active: true,
464
+ lastProvisionedAt: Date.now(),
465
+ ...args.raw === void 0 ? {} : { raw: args.raw }
466
+ });
467
+ return await replaceScimGroupMembers(ctx, args.groupId, args.memberIds, args.roleIds, args.cursor);
468
+ }
469
+ });
470
+ /**
471
+ * Revoke a SCIM group in bounded membership pages. The identity and group are
472
+ * removed only when the final page returns `isDone`.
473
+ */
474
+ const revokeGroup = mutation({
475
+ args: {
476
+ connectionId: v.id("GroupConnection"),
477
+ groupId: v.id("Group"),
478
+ cursor: v.optional(v.string())
479
+ },
480
+ returns: vScimMembershipProgress,
481
+ handler: async (ctx, args) => {
482
+ const connection = await activeScimConnection(ctx, args.connectionId);
483
+ const identity = await ctx.db.query("GroupConnectionScimIdentity").withIndex("mapped_group_id", (idx) => idx.eq("mappedGroupId", args.groupId)).unique();
484
+ if (identity === null || identity.connectionId !== args.connectionId || identity.groupId !== connection.groupId || identity.resourceType !== "group") throw new ConvexError({
485
+ code: ErrorCode.ACCOUNT_NOT_FOUND,
486
+ message: "SCIM group not found."
487
+ });
488
+ const group = await ctx.db.get("Group", args.groupId);
489
+ if (group === null || group.parentGroupId !== identity.groupId) throw new ConvexError({
490
+ code: ErrorCode.INVALID_PARAMETERS,
491
+ message: "SCIM group ownership mismatch."
492
+ });
493
+ const members = await paginator(ctx.db, schema_default).query("GroupMember").withIndex("group_id", (idx) => idx.eq("groupId", args.groupId)).paginate({
494
+ numItems: SCIM_GROUP_MEMBERSHIP_BATCH_SIZE,
495
+ cursor: args.cursor ?? null
496
+ });
497
+ for (const member of members.page) await ctx.db.delete("GroupMember", member._id);
498
+ if (members.isDone) {
499
+ await ctx.db.delete("GroupConnectionScimIdentity", identity._id);
500
+ await ctx.db.delete("Group", args.groupId);
501
+ }
502
+ return {
503
+ isDone: members.isDone,
504
+ continueCursor: members.continueCursor
505
+ };
506
+ }
507
+ });
160
508
 
161
509
  //#endregion
162
- export { get, list, provision, remove, upsert };
510
+ export { get, list, provision, provisionGroup, revoke, revokeGroup, update, updateGroup };
163
511
  //# sourceMappingURL=identity.js.map