@robelest/convex-auth 0.0.4-preview.22 → 0.0.4-preview.24

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 (314) hide show
  1. package/README.md +10 -11
  2. package/dist/authorization/index.d.ts +1 -1
  3. package/dist/authorization/index.js +1 -1
  4. package/dist/authorization/index.js.map +1 -1
  5. package/dist/client/index.d.ts +1 -2
  6. package/dist/client/index.d.ts.map +1 -1
  7. package/dist/client/index.js +36 -39
  8. package/dist/client/index.js.map +1 -1
  9. package/dist/component/client/index.d.ts +1 -2
  10. package/dist/component/index.js +2 -2
  11. package/dist/component/model.d.ts +9 -9
  12. package/dist/component/model.d.ts.map +1 -1
  13. package/dist/component/public/enterprise/audit.d.ts.map +1 -1
  14. package/dist/component/public/enterprise/audit.js.map +1 -1
  15. package/dist/component/public/enterprise/core.d.ts.map +1 -1
  16. package/dist/component/public/enterprise/core.js.map +1 -1
  17. package/dist/component/public/enterprise/domains.d.ts.map +1 -1
  18. package/dist/component/public/enterprise/domains.js.map +1 -1
  19. package/dist/component/public/enterprise/scim.d.ts.map +1 -1
  20. package/dist/component/public/enterprise/scim.js.map +1 -1
  21. package/dist/component/public/enterprise/secrets.d.ts.map +1 -1
  22. package/dist/component/public/enterprise/secrets.js.map +1 -1
  23. package/dist/component/public/enterprise/webhooks.d.ts.map +1 -1
  24. package/dist/component/public/enterprise/webhooks.js.map +1 -1
  25. package/dist/component/public/factors/devices.d.ts.map +1 -1
  26. package/dist/component/public/factors/devices.js.map +1 -1
  27. package/dist/component/public/factors/passkeys.d.ts.map +1 -1
  28. package/dist/component/public/factors/passkeys.js.map +1 -1
  29. package/dist/component/public/factors/totp.d.ts.map +1 -1
  30. package/dist/component/public/factors/totp.js.map +1 -1
  31. package/dist/component/public/groups/core.js.map +1 -1
  32. package/dist/component/public/groups/invites.d.ts.map +1 -1
  33. package/dist/component/public/groups/invites.js.map +1 -1
  34. package/dist/component/public/groups/members.d.ts.map +1 -1
  35. package/dist/component/public/groups/members.js.map +1 -1
  36. package/dist/component/public/identity/accounts.d.ts.map +1 -1
  37. package/dist/component/public/identity/accounts.js.map +1 -1
  38. package/dist/component/public/identity/codes.d.ts.map +1 -1
  39. package/dist/component/public/identity/codes.js.map +1 -1
  40. package/dist/component/public/identity/sessions.d.ts.map +1 -1
  41. package/dist/component/public/identity/sessions.js.map +1 -1
  42. package/dist/component/public/identity/tokens.d.ts.map +1 -1
  43. package/dist/component/public/identity/tokens.js.map +1 -1
  44. package/dist/component/public/identity/users.d.ts.map +1 -1
  45. package/dist/component/public/identity/users.js.map +1 -1
  46. package/dist/component/public/identity/verifiers.d.ts.map +1 -1
  47. package/dist/component/public/identity/verifiers.js.map +1 -1
  48. package/dist/component/public/security/keys.d.ts.map +1 -1
  49. package/dist/component/public/security/keys.js.map +1 -1
  50. package/dist/component/public/security/limits.d.ts.map +1 -1
  51. package/dist/component/public/security/limits.js.map +1 -1
  52. package/dist/component/schema.d.ts +41 -41
  53. package/dist/component/server/auth.d.ts +127 -130
  54. package/dist/component/server/auth.d.ts.map +1 -1
  55. package/dist/component/server/auth.js +100 -64
  56. package/dist/component/server/auth.js.map +1 -1
  57. package/dist/component/server/context.js +53 -0
  58. package/dist/component/server/context.js.map +1 -0
  59. package/dist/component/server/core.js +113 -250
  60. package/dist/component/server/core.js.map +1 -1
  61. package/dist/component/server/crypto.js +25 -7
  62. package/dist/component/server/crypto.js.map +1 -1
  63. package/dist/component/server/device.js +59 -16
  64. package/dist/component/server/device.js.map +1 -1
  65. package/dist/component/server/enterprise/domain.js +148 -59
  66. package/dist/component/server/enterprise/domain.js.map +1 -1
  67. package/dist/component/server/enterprise/http.js +36 -15
  68. package/dist/component/server/enterprise/http.js.map +1 -1
  69. package/dist/component/server/enterprise/oidc.js +1 -1
  70. package/dist/component/server/http.d.ts +85 -0
  71. package/dist/component/server/http.d.ts.map +1 -0
  72. package/dist/component/server/http.js +85 -22
  73. package/dist/component/server/http.js.map +1 -1
  74. package/dist/component/server/identity.js +5 -2
  75. package/dist/component/server/identity.js.map +1 -1
  76. package/dist/component/server/limits.js +21 -30
  77. package/dist/component/server/limits.js.map +1 -1
  78. package/dist/component/server/mutations/account.js +12 -10
  79. package/dist/component/server/mutations/account.js.map +1 -1
  80. package/dist/component/server/mutations/code.js +5 -2
  81. package/dist/component/server/mutations/code.js.map +1 -1
  82. package/dist/component/server/mutations/invalidate.js +1 -1
  83. package/dist/component/server/mutations/invalidate.js.map +1 -1
  84. package/dist/component/server/mutations/oauth.js +10 -4
  85. package/dist/component/server/mutations/oauth.js.map +1 -1
  86. package/dist/component/server/mutations/refresh.js +2 -2
  87. package/dist/component/server/mutations/refresh.js.map +1 -1
  88. package/dist/component/server/mutations/register.js +46 -42
  89. package/dist/component/server/mutations/register.js.map +1 -1
  90. package/dist/component/server/mutations/retrieve.js +21 -25
  91. package/dist/component/server/mutations/retrieve.js.map +1 -1
  92. package/dist/component/server/mutations/signature.js +10 -4
  93. package/dist/component/server/mutations/signature.js.map +1 -1
  94. package/dist/component/server/mutations/signout.js.map +1 -1
  95. package/dist/component/server/mutations/store.js +9 -24
  96. package/dist/component/server/mutations/store.js.map +1 -1
  97. package/dist/component/server/mutations/verifier.js.map +1 -1
  98. package/dist/component/server/mutations/verify.js +1 -1
  99. package/dist/component/server/mutations/verify.js.map +1 -1
  100. package/dist/component/server/oauth.js +53 -16
  101. package/dist/component/server/oauth.js.map +1 -1
  102. package/dist/component/server/passkey.js +115 -31
  103. package/dist/component/server/passkey.js.map +1 -1
  104. package/dist/component/server/redirects.js +9 -3
  105. package/dist/component/server/redirects.js.map +1 -1
  106. package/dist/component/server/refresh.js +10 -7
  107. package/dist/component/server/refresh.js.map +1 -1
  108. package/dist/component/server/runtime.d.ts +5 -5
  109. package/dist/component/server/runtime.js +156 -113
  110. package/dist/component/server/runtime.js.map +1 -1
  111. package/dist/component/server/signin.js +34 -10
  112. package/dist/component/server/signin.js.map +1 -1
  113. package/dist/component/server/totp.js +79 -19
  114. package/dist/component/server/totp.js.map +1 -1
  115. package/dist/component/server/types.d.ts +12 -20
  116. package/dist/component/server/types.d.ts.map +1 -1
  117. package/dist/component/server/types.js.map +1 -1
  118. package/dist/component/server/users.js +6 -3
  119. package/dist/component/server/users.js.map +1 -1
  120. package/dist/component/server/utils.js +10 -4
  121. package/dist/component/server/utils.js.map +1 -1
  122. package/dist/core/types.d.ts +14 -22
  123. package/dist/core/types.d.ts.map +1 -1
  124. package/dist/factors/device.js +8 -9
  125. package/dist/factors/device.js.map +1 -1
  126. package/dist/factors/passkey.js +18 -21
  127. package/dist/factors/passkey.js.map +1 -1
  128. package/dist/providers/password.js +66 -81
  129. package/dist/providers/password.js.map +1 -1
  130. package/dist/runtime/invite.js +2 -8
  131. package/dist/runtime/invite.js.map +1 -1
  132. package/dist/server/auth.d.ts +127 -130
  133. package/dist/server/auth.d.ts.map +1 -1
  134. package/dist/server/auth.js +100 -64
  135. package/dist/server/auth.js.map +1 -1
  136. package/dist/server/context.d.ts +1 -0
  137. package/dist/server/context.js +53 -0
  138. package/dist/server/context.js.map +1 -0
  139. package/dist/server/core.d.ts +74 -195
  140. package/dist/server/core.d.ts.map +1 -1
  141. package/dist/server/core.js +113 -250
  142. package/dist/server/core.js.map +1 -1
  143. package/dist/server/crypto.d.ts.map +1 -1
  144. package/dist/server/crypto.js +25 -7
  145. package/dist/server/crypto.js.map +1 -1
  146. package/dist/server/device.js +59 -16
  147. package/dist/server/device.js.map +1 -1
  148. package/dist/server/enterprise/domain.d.ts +0 -8
  149. package/dist/server/enterprise/domain.d.ts.map +1 -1
  150. package/dist/server/enterprise/domain.js +148 -59
  151. package/dist/server/enterprise/domain.js.map +1 -1
  152. package/dist/server/enterprise/http.d.ts.map +1 -1
  153. package/dist/server/enterprise/http.js +35 -14
  154. package/dist/server/enterprise/http.js.map +1 -1
  155. package/dist/server/http.d.ts +81 -3
  156. package/dist/server/http.d.ts.map +1 -1
  157. package/dist/server/http.js +84 -21
  158. package/dist/server/http.js.map +1 -1
  159. package/dist/server/identity.js +5 -2
  160. package/dist/server/identity.js.map +1 -1
  161. package/dist/server/index.d.ts +3 -2
  162. package/dist/server/index.js +2 -2
  163. package/dist/server/limits.js +21 -30
  164. package/dist/server/limits.js.map +1 -1
  165. package/dist/server/mounts.d.ts +25 -63
  166. package/dist/server/mounts.d.ts.map +1 -1
  167. package/dist/server/mounts.js +46 -107
  168. package/dist/server/mounts.js.map +1 -1
  169. package/dist/server/mutations/account.d.ts +8 -9
  170. package/dist/server/mutations/account.d.ts.map +1 -1
  171. package/dist/server/mutations/account.js +11 -9
  172. package/dist/server/mutations/account.js.map +1 -1
  173. package/dist/server/mutations/code.d.ts +12 -12
  174. package/dist/server/mutations/code.d.ts.map +1 -1
  175. package/dist/server/mutations/code.js +5 -2
  176. package/dist/server/mutations/code.js.map +1 -1
  177. package/dist/server/mutations/invalidate.d.ts +4 -4
  178. package/dist/server/mutations/invalidate.d.ts.map +1 -1
  179. package/dist/server/mutations/invalidate.js.map +1 -1
  180. package/dist/server/mutations/oauth.d.ts +14 -12
  181. package/dist/server/mutations/oauth.d.ts.map +1 -1
  182. package/dist/server/mutations/oauth.js +9 -3
  183. package/dist/server/mutations/oauth.js.map +1 -1
  184. package/dist/server/mutations/refresh.d.ts +3 -3
  185. package/dist/server/mutations/refresh.d.ts.map +1 -1
  186. package/dist/server/mutations/refresh.js +1 -1
  187. package/dist/server/mutations/refresh.js.map +1 -1
  188. package/dist/server/mutations/register.d.ts +11 -11
  189. package/dist/server/mutations/register.d.ts.map +1 -1
  190. package/dist/server/mutations/register.js +45 -41
  191. package/dist/server/mutations/register.js.map +1 -1
  192. package/dist/server/mutations/retrieve.d.ts +6 -6
  193. package/dist/server/mutations/retrieve.d.ts.map +1 -1
  194. package/dist/server/mutations/retrieve.js +20 -24
  195. package/dist/server/mutations/retrieve.js.map +1 -1
  196. package/dist/server/mutations/signature.d.ts +6 -7
  197. package/dist/server/mutations/signature.d.ts.map +1 -1
  198. package/dist/server/mutations/signature.js +9 -3
  199. package/dist/server/mutations/signature.js.map +1 -1
  200. package/dist/server/mutations/signin.d.ts +5 -5
  201. package/dist/server/mutations/signout.js.map +1 -1
  202. package/dist/server/mutations/store.d.ts +83 -83
  203. package/dist/server/mutations/store.js +8 -23
  204. package/dist/server/mutations/store.js.map +1 -1
  205. package/dist/server/mutations/verifier.js.map +1 -1
  206. package/dist/server/mutations/verify.d.ts +7 -7
  207. package/dist/server/mutations/verify.d.ts.map +1 -1
  208. package/dist/server/mutations/verify.js.map +1 -1
  209. package/dist/server/oauth.js +53 -16
  210. package/dist/server/oauth.js.map +1 -1
  211. package/dist/server/passkey.d.ts +2 -2
  212. package/dist/server/passkey.d.ts.map +1 -1
  213. package/dist/server/passkey.js +114 -30
  214. package/dist/server/passkey.js.map +1 -1
  215. package/dist/server/redirects.js +9 -3
  216. package/dist/server/redirects.js.map +1 -1
  217. package/dist/server/refresh.js +10 -7
  218. package/dist/server/refresh.js.map +1 -1
  219. package/dist/server/runtime.d.ts +11 -11
  220. package/dist/server/runtime.js +155 -112
  221. package/dist/server/runtime.js.map +1 -1
  222. package/dist/server/signin.js +34 -10
  223. package/dist/server/signin.js.map +1 -1
  224. package/dist/server/ssr.d.ts.map +1 -1
  225. package/dist/server/ssr.js +175 -184
  226. package/dist/server/ssr.js.map +1 -1
  227. package/dist/server/totp.js +78 -18
  228. package/dist/server/totp.js.map +1 -1
  229. package/dist/server/types.d.ts +13 -21
  230. package/dist/server/types.d.ts.map +1 -1
  231. package/dist/server/types.js.map +1 -1
  232. package/dist/server/users.js +6 -3
  233. package/dist/server/users.js.map +1 -1
  234. package/dist/server/utils.js +10 -4
  235. package/dist/server/utils.js.map +1 -1
  236. package/package.json +1 -5
  237. package/src/authorization/index.ts +1 -1
  238. package/src/client/core/types.ts +14 -14
  239. package/src/client/factors/device.ts +10 -12
  240. package/src/client/factors/passkey.ts +23 -26
  241. package/src/client/index.ts +54 -64
  242. package/src/client/runtime/invite.ts +5 -7
  243. package/src/component/index.ts +9 -3
  244. package/src/component/public/enterprise/audit.ts +6 -1
  245. package/src/component/public/enterprise/core.ts +1 -0
  246. package/src/component/public/enterprise/domains.ts +5 -1
  247. package/src/component/public/enterprise/scim.ts +1 -0
  248. package/src/component/public/enterprise/secrets.ts +1 -0
  249. package/src/component/public/enterprise/webhooks.ts +1 -0
  250. package/src/component/public/factors/devices.ts +1 -0
  251. package/src/component/public/factors/passkeys.ts +1 -0
  252. package/src/component/public/factors/totp.ts +1 -0
  253. package/src/component/public/groups/core.ts +1 -1
  254. package/src/component/public/groups/invites.ts +7 -1
  255. package/src/component/public/groups/members.ts +1 -0
  256. package/src/component/public/identity/accounts.ts +1 -0
  257. package/src/component/public/identity/codes.ts +1 -0
  258. package/src/component/public/identity/sessions.ts +1 -0
  259. package/src/component/public/identity/tokens.ts +1 -0
  260. package/src/component/public/identity/users.ts +1 -0
  261. package/src/component/public/identity/verifiers.ts +1 -0
  262. package/src/component/public/security/keys.ts +1 -0
  263. package/src/component/public/security/limits.ts +1 -0
  264. package/src/providers/password.ts +89 -110
  265. package/src/server/auth.ts +240 -182
  266. package/src/server/context.ts +90 -0
  267. package/src/server/core.ts +195 -286
  268. package/src/server/crypto.ts +31 -29
  269. package/src/server/device.ts +65 -32
  270. package/src/server/enterprise/domain.ts +158 -170
  271. package/src/server/enterprise/http.ts +46 -39
  272. package/src/server/http.ts +289 -30
  273. package/src/server/identity.ts +5 -5
  274. package/src/server/index.ts +9 -3
  275. package/src/server/limits.ts +53 -80
  276. package/src/server/mounts.ts +56 -80
  277. package/src/server/mutations/account.ts +22 -36
  278. package/src/server/mutations/code.ts +6 -6
  279. package/src/server/mutations/invalidate.ts +1 -1
  280. package/src/server/mutations/oauth.ts +14 -8
  281. package/src/server/mutations/refresh.ts +5 -4
  282. package/src/server/mutations/register.ts +87 -132
  283. package/src/server/mutations/retrieve.ts +44 -44
  284. package/src/server/mutations/signature.ts +13 -6
  285. package/src/server/mutations/signout.ts +1 -1
  286. package/src/server/mutations/store.ts +16 -31
  287. package/src/server/mutations/verifier.ts +1 -1
  288. package/src/server/mutations/verify.ts +3 -5
  289. package/src/server/oauth.ts +60 -69
  290. package/src/server/passkey.ts +567 -517
  291. package/src/server/redirects.ts +10 -6
  292. package/src/server/refresh.ts +14 -18
  293. package/src/server/runtime.ts +340 -302
  294. package/src/server/signin.ts +44 -37
  295. package/src/server/ssr.ts +390 -407
  296. package/src/server/totp.ts +85 -35
  297. package/src/server/types.ts +19 -22
  298. package/src/server/users.ts +7 -6
  299. package/src/server/utils.ts +10 -12
  300. package/dist/component/server/authError.js +0 -34
  301. package/dist/component/server/authError.js.map +0 -1
  302. package/dist/component/server/errors.d.ts +0 -1
  303. package/dist/component/server/errors.js +0 -137
  304. package/dist/component/server/errors.js.map +0 -1
  305. package/dist/server/authError.d.ts +0 -46
  306. package/dist/server/authError.d.ts.map +0 -1
  307. package/dist/server/authError.js +0 -34
  308. package/dist/server/authError.js.map +0 -1
  309. package/dist/server/errors.d.ts +0 -177
  310. package/dist/server/errors.d.ts.map +0 -1
  311. package/dist/server/errors.js +0 -212
  312. package/dist/server/errors.js.map +0 -1
  313. package/src/server/authError.ts +0 -44
  314. package/src/server/errors.ts +0 -290
@@ -1 +1 @@
1
- {"version":3,"file":"http.js","names":["serializeCookie","state"],"sources":["../../../src/server/enterprise/http.ts"],"sourcesContent":["import type { GenericActionCtx, HttpRouter } from \"convex/server\";\nimport { serialize as serializeCookie } from \"cookie\";\n\nimport { redirectToParamCookie, useRedirectToParam } from \"../cookies\";\nimport { isAuthError } from \"../errors\";\nimport { Fx } from \"@robelest/fx\";\n\nimport { AuthError } from \"../authError\";\nimport { addSSORoutes, convertErrorsToResponse, getCookies } from \"../http\";\nimport type { SSORuntimeRoute } from \"../http\";\nimport { createOAuthAuthorizationURL, handleOAuthCallback } from \"../oauth\";\nimport { redirectAbsoluteUrl, setURLSearchParam } from \"../redirects\";\nimport { createEnterpriseOidcRuntime } from \"./oidc\";\nimport {\n createEnterpriseSamlMetadataXml,\n createEnterpriseSamlSignInRequest,\n createSamlPostBindingResponse,\n encodeEnterpriseSamlRelayState,\n parseEnterpriseSamlLoginResponse,\n parseEnterpriseSamlLogoutMessage,\n profileFromSamlExtract,\n validateEnterpriseSamlLoginRelayState,\n} from \"./saml\";\nimport {\n parseScimListRequest,\n scimError,\n scimJson,\n serializeScimGroup,\n serializeScimUser,\n} from \"./scim\";\nimport {\n enterpriseSamlProviderId,\n SCIM_GROUP_SCHEMA_ID,\n SCIM_USER_SCHEMA_ID,\n} from \"./shared\";\n\nexport type EnterpriseHttpRuntimeDeps = {\n http: HttpRouter;\n hasSSO: boolean;\n auth: any;\n config: any;\n routeBase: string;\n requireEnv: (name: string) => string;\n loadActiveEnterpriseSamlOrThrow: any;\n loadEnterpriseOidcOrThrow: any;\n getEnterpriseScimContext: any;\n getPolicyFromEnterprise: any;\n normalizeEnterprisePolicy: any;\n recordEnterpriseAuditEvent: any;\n emitEnterpriseWebhookDeliveries: any;\n generateRandomString: (length: number, alphabet: string) => string;\n inviteTokenAlphabet: string;\n callUserOAuth: any;\n callVerifierSignature: any;\n};\n\nexport function addEnterpriseHttpRuntime(deps: EnterpriseHttpRuntimeDeps) {\n if (!deps.hasSSO) {\n return;\n }\n\n const {\n http,\n auth,\n config,\n requireEnv,\n loadActiveEnterpriseSamlOrThrow,\n loadEnterpriseOidcOrThrow,\n getEnterpriseScimContext,\n getPolicyFromEnterprise,\n recordEnterpriseAuditEvent,\n emitEnterpriseWebhookDeliveries,\n generateRandomString,\n inviteTokenAlphabet: INVITE_TOKEN_ALPHABET,\n callUserOAuth,\n callVerifierSignature,\n } = deps;\n const ENTERPRISE_CONTROL_ROUTE_BASE = deps.routeBase;\n\n type ScimState = {\n ctx: any;\n request: Request;\n url: URL;\n parsedPath: Awaited<\n ReturnType<typeof getEnterpriseScimContext>\n >[\"parsedPath\"];\n enterprise: Awaited<\n ReturnType<typeof getEnterpriseScimContext>\n >[\"enterprise\"];\n scimConfig: Awaited<\n ReturnType<typeof getEnterpriseScimContext>\n >[\"scimConfig\"];\n policy: any;\n recordScimEvent: (\n eventType: string,\n ok: boolean,\n subjectType: string,\n subjectId?: string,\n metadata?: Record<string, unknown>,\n ) => Promise<void>;\n };\n\n type ScimHandler = (state: ScimState) => Promise<Response>;\n\n const SCIM_SCHEMAS = [\n {\n id: SCIM_USER_SCHEMA_ID,\n name: \"User\",\n description: \"User Account\",\n attributes: [\n { name: \"userName\", type: \"string\", required: true },\n { name: \"displayName\", type: \"string\" },\n { name: \"active\", type: \"boolean\" },\n { name: \"emails\", type: \"complex\", multiValued: true },\n ],\n },\n {\n id: SCIM_GROUP_SCHEMA_ID,\n name: \"Group\",\n description: \"Group\",\n attributes: [\n { name: \"displayName\", type: \"string\", required: true },\n { name: \"members\", type: \"complex\", multiValued: true },\n ],\n },\n ] as const;\n\n const SCIM_RESOURCE_TYPES = [\n {\n id: \"User\",\n name: \"User\",\n endpoint: \"/Users\",\n schema: SCIM_USER_SCHEMA_ID,\n },\n {\n id: \"Group\",\n name: \"Group\",\n endpoint: \"/Groups\",\n schema: SCIM_GROUP_SCHEMA_ID,\n },\n ] as const;\n\n const handleStaticScimCollection = <T extends { id?: string; name?: string }>(\n items: readonly T[],\n resourceId: string | undefined,\n opts: { by: \"id\" | \"name\"; notFound: string },\n ) => {\n if (resourceId !== undefined) {\n const item = items.find(\n (entry) => entry[opts.by] === decodeURIComponent(resourceId),\n );\n return item ? scimJson(item) : scimError(404, \"notFound\", opts.notFound);\n }\n return scimJson({\n schemas: [\"urn:ietf:params:scim:api:messages:2.0:ListResponse\"],\n Resources: items,\n totalResults: items.length,\n startIndex: 1,\n itemsPerPage: items.length,\n });\n };\n\n const filterScimCollection = <T>(\n items: T[],\n filter: ReturnType<typeof parseScimListRequest>[\"filter\"],\n filters: Record<string, (item: T, value: string) => boolean>,\n ) => {\n if (!filter) {\n return items;\n }\n const predicate = filters[filter.attribute];\n if (!predicate) {\n throw new Error(\"Unsupported SCIM filter.\");\n }\n return items.filter((item) => predicate(item, filter.value));\n };\n\n const paginateScimCollection = <T>(\n items: T[],\n listRequest: ReturnType<typeof parseScimListRequest>,\n ) => {\n const start = listRequest.startIndex - 1;\n return items.slice(start, start + listRequest.count);\n };\n\n const requireScimResourceId = (\n resourceId: string | undefined,\n label: string,\n ) => {\n if (!resourceId) {\n return scimError(400, \"invalidPath\", `${label} resource ID is required.`);\n }\n return null;\n };\n\n const readScimJson = async (request: Request) =>\n (await request.json()) as Record<string, any>;\n\n const handleSamlAcs = async (\n ctx: GenericActionCtx<any>,\n request: Request,\n runtimeRoute: SSORuntimeRoute,\n ) =>\n Fx.run(\n Fx.gen(function* () {\n yield* Fx.guard(\n runtimeRoute.protocol !== \"saml\" ||\n runtimeRoute.rest.length !== 1 ||\n runtimeRoute.rest[0] !== \"acs\",\n Fx.fail(\n new AuthError(\n \"INVALID_PARAMETERS\",\n \"Invalid enterprise runtime path.\",\n ).toConvexError(),\n ),\n );\n\n const enterpriseId = runtimeRoute.enterpriseId;\n const { loaded, enterprise, saml } = yield* Fx.from({\n ok: () => loadActiveEnterpriseSamlOrThrow(ctx, enterpriseId),\n err: (e) => e,\n });\n\n const parsedResponse = yield* Fx.from({\n ok: () =>\n parseEnterpriseSamlLoginResponse({\n request,\n rootUrl: requireEnv(\"CONVEX_SITE_URL\"),\n source: { kind: \"enterprise\", id: enterprise._id },\n config: loaded.config,\n }),\n err: (e) =>\n new AuthError(\n \"OAUTH_PROVIDER_ERROR\",\n `SAML response parse failed: ${e instanceof Error ? e.message : String(e)}`,\n ).toConvexError(),\n });\n\n yield* Fx.from({\n ok: () => {\n validateEnterpriseSamlLoginRelayState({\n relayState: parsedResponse.relayState,\n source: { kind: \"enterprise\", id: enterprise._id },\n inResponseTo:\n parsedResponse.parsed.extract?.response?.inResponseTo,\n });\n return Promise.resolve();\n },\n err: () =>\n new AuthError(\n \"OAUTH_INVALID_STATE\",\n \"SAML RelayState did not match the pending login request.\",\n ).toConvexError(),\n });\n\n const { samlAttributes, samlSessionIndex, ...userProfile } =\n profileFromSamlExtract(\n parsedResponse.parsed.extract,\n saml.attributeMapping,\n );\n const profile = userProfile as Record<string, unknown> & {\n id: string;\n };\n\n const maybeRedirectTo = useRedirectToParam(\n enterpriseSamlProviderId(enterprise._id),\n getCookies(request),\n );\n\n const verificationCode = yield* Fx.from({\n ok: () =>\n callUserOAuth(ctx, {\n provider: enterpriseSamlProviderId(enterprise._id),\n providerAccountId: profile.id,\n profile,\n signature: parsedResponse.relayState.signature,\n accountExtend: {\n identity: {\n protocol: \"saml\",\n enterpriseId: enterprise._id,\n subject: profile.id,\n entityId:\n typeof saml.entityId === \"string\"\n ? saml.entityId\n : undefined,\n },\n saml: {\n attributes: samlAttributes,\n sessionIndex: samlSessionIndex,\n },\n },\n }),\n err: (e) => e,\n });\n\n const destinationUrl = yield* Fx.from({\n ok: () =>\n redirectAbsoluteUrl(config, {\n redirectTo:\n maybeRedirectTo?.redirectTo ??\n (typeof parsedResponse.relayState.redirectTo === \"string\"\n ? parsedResponse.relayState.redirectTo\n : undefined),\n }),\n err: (e) => e,\n });\n\n const vurl = setURLSearchParam(\n destinationUrl,\n \"code\",\n verificationCode,\n );\n const vheaders = new Headers({ Location: vurl });\n vheaders.set(\"Cache-Control\", \"must-revalidate\");\n for (const { name, value, options } of maybeRedirectTo !== null\n ? [maybeRedirectTo.updatedCookie]\n : []) {\n vheaders.append(\"Set-Cookie\", serializeCookie(name, value, options));\n }\n return new Response(null, { status: 302, headers: vheaders });\n }).pipe(Fx.recover((e) => Fx.fatal(e))),\n );\n\n const handleSamlSlo = async (\n ctx: GenericActionCtx<any>,\n request: Request,\n runtimeRoute: SSORuntimeRoute,\n ) => {\n if (\n runtimeRoute.protocol !== \"saml\" ||\n runtimeRoute.rest.length !== 1 ||\n runtimeRoute.rest[0] !== \"slo\"\n ) {\n throw new AuthError(\n \"INVALID_PARAMETERS\",\n \"Invalid enterprise runtime path.\",\n ).toConvexError();\n }\n const { loaded, enterprise } = await loadActiveEnterpriseSamlOrThrow(\n ctx,\n runtimeRoute.enterpriseId,\n );\n const parsedMessage = await parseEnterpriseSamlLogoutMessage({\n request,\n rootUrl: requireEnv(\"CONVEX_SITE_URL\"),\n source: { kind: \"enterprise\", id: enterprise._id },\n config: loaded.config,\n });\n if (parsedMessage.hasSamlRequest && parsedMessage.parsedRequest) {\n const responseContext = (\n parsedMessage.runtime.sp as any\n ).createLogoutResponse(\n parsedMessage.runtime.idp as any,\n parsedMessage.parsedRequest.extract,\n parsedMessage.binding as any,\n parsedMessage.relayState ?? \"\",\n ) as any;\n if (parsedMessage.binding === \"redirect\") {\n return new Response(null, {\n status: 302,\n headers: { Location: responseContext.context },\n });\n }\n return createSamlPostBindingResponse({\n endpoint: responseContext.entityEndpoint,\n parameter: \"SAMLResponse\",\n value: responseContext.context,\n relayState: parsedMessage.relayState,\n });\n }\n if (parsedMessage.hasSamlResponse) {\n return new Response(null, { status: 204 });\n }\n throw new AuthError(\n \"INVALID_PARAMETERS\",\n \"Missing SAML logout payload.\",\n ).toConvexError();\n };\n\n const handleScimRequest = async (\n ctx: GenericActionCtx<any>,\n request: Request,\n ) => {\n try {\n const { scimConfig, enterprise, parsedPath } =\n await getEnterpriseScimContext(ctx, request);\n const url = new URL(request.url);\n const state: ScimState = {\n ctx,\n request,\n url,\n parsedPath,\n enterprise,\n scimConfig,\n policy: getPolicyFromEnterprise(enterprise),\n recordScimEvent: async (\n eventType,\n ok,\n subjectType,\n subjectId,\n metadata,\n ) => {\n const auditEventId = await recordEnterpriseAuditEvent(ctx, {\n enterpriseId: enterprise._id,\n groupId: enterprise.groupId,\n eventType,\n actorType: \"scim\",\n subjectType,\n subjectId,\n ok,\n metadata,\n });\n await emitEnterpriseWebhookDeliveries(ctx, {\n enterpriseId: enterprise._id,\n eventType,\n auditEventId,\n payload: {\n enterpriseId: enterprise._id,\n subjectId,\n metadata,\n },\n });\n },\n };\n\n const handleUsersGet: ScimHandler = async (state) => {\n const members = await auth.member.list(state.ctx, {\n where: { groupId: state.enterprise.groupId },\n limit: 100,\n });\n const identities = await state.ctx.runQuery(\n config.component.public.enterpriseScimIdentityListByEnterprise,\n { enterpriseId: state.enterprise._id },\n );\n const identityByUserId = new Map(\n identities\n .filter((identity: any) => identity.userId !== undefined)\n .map((identity: any) => [identity.userId, identity]),\n );\n const users = (\n await Promise.all(\n members.items.map(async (member: any) => {\n const user = await auth.user.get(state.ctx, member.userId);\n return user\n ? {\n user,\n member,\n identity: identityByUserId.get(user._id),\n }\n : null;\n }),\n )\n ).filter(Boolean) as Array<{\n user: any;\n member: any;\n identity?: any;\n }>;\n const listRequest = parseScimListRequest(state.url);\n const filtered = filterScimCollection(users, listRequest.filter, {\n id: (item: { user: any }, value: string) => item.user._id === value,\n externalId: (item: { identity?: any }, value: string) =>\n item.identity?.externalId === value,\n userName: (item: { user: any }, value: string) =>\n item.user.email === value,\n \"emails.value\": (item: { user: any }, value: string) =>\n item.user.email === value,\n active: (item: { identity?: any; member: any }, value: string) =>\n String(item.identity?.active ?? item.member.status === \"active\") ===\n value,\n });\n if (state.parsedPath.resourceId) {\n const resource = filtered.find(\n ({ user }) => user._id === state.parsedPath.resourceId,\n );\n return resource\n ? scimJson(\n serializeScimUser({\n id: resource.user._id,\n user: resource.user,\n externalId: resource.identity?.externalId,\n location: `${state.url.origin}${state.url.pathname.replace(/\\/[^/]+$/, \"\")}/${resource.user._id}`,\n active:\n resource.identity?.active ??\n resource.member.status === \"active\",\n }),\n 200,\n {\n Location: `${state.url.origin}${state.url.pathname.replace(/\\/[^/]+$/, \"\")}/${resource.user._id}`,\n },\n )\n : scimError(404, \"notFound\", \"User not found.\");\n }\n const paged = paginateScimCollection(filtered, listRequest);\n await state.recordScimEvent(\n \"enterprise.scim.read\",\n true,\n \"enterprise_scim\",\n state.scimConfig._id,\n );\n return scimJson({\n schemas: [\"urn:ietf:params:scim:api:messages:2.0:ListResponse\"],\n Resources: paged.map(({ user, identity, member }) =>\n serializeScimUser({\n id: user._id,\n user,\n externalId: identity?.externalId,\n location: `${state.url.origin}${state.url.pathname}/${user._id}`,\n active: identity?.active ?? member.status === \"active\",\n }),\n ),\n totalResults: filtered.length,\n startIndex: listRequest.startIndex,\n itemsPerPage: paged.length,\n });\n };\n\n const handleUsersPost: ScimHandler = async (state) => {\n const body = await readScimJson(state.request);\n const primaryEmail = Array.isArray(body.emails)\n ? (body.emails.find((entry) => entry.primary === true)?.value ??\n body.emails[0]?.value)\n : undefined;\n const phone = Array.isArray(body.phoneNumbers)\n ? body.phoneNumbers[0]?.value\n : undefined;\n const userId = (await state.ctx.runMutation(\n config.component.public.userInsert,\n {\n data: {\n name: body.displayName ?? body.name?.formatted,\n email: primaryEmail ?? body.userName,\n ...(typeof (primaryEmail ?? body.userName) === \"string\"\n ? { emailVerificationTime: Date.now() }\n : {}),\n phone,\n ...(typeof phone === \"string\"\n ? { phoneVerificationTime: Date.now() }\n : {}),\n },\n },\n )) as string;\n try {\n await auth.member.create(state.ctx, {\n groupId: state.enterprise.groupId,\n userId,\n roleIds: state.policy.provisioning.jit.defaultRoleIds,\n status: body.active === false ? \"inactive\" : \"active\",\n });\n } catch {}\n if (typeof body.externalId === \"string\") {\n await state.ctx.runMutation(\n config.component.public.enterpriseScimIdentityUpsert,\n {\n enterpriseId: state.enterprise._id,\n groupId: state.enterprise.groupId,\n resourceType: \"user\",\n externalId: body.externalId,\n userId,\n active: body.active !== false,\n raw: body,\n lastProvisionedAt: Date.now(),\n },\n );\n }\n await state.recordScimEvent(\n \"enterprise.scim.user.created\",\n true,\n \"user\",\n userId,\n );\n const createdUser = await auth.user.get(state.ctx, userId);\n const location = `${state.url.origin}${state.url.pathname}/${userId}`;\n return scimJson(\n serializeScimUser({\n id: userId,\n user: createdUser ?? {},\n externalId: body.externalId,\n location,\n active: body.active !== false,\n }),\n 201,\n { Location: location },\n );\n };\n\n const handleUsersUpsert: ScimHandler = async (state) => {\n const missing = requireScimResourceId(\n state.parsedPath.resourceId,\n \"User\",\n );\n if (missing) return missing;\n const userId = state.parsedPath.resourceId!;\n const existingUser = await auth.user.get(state.ctx, userId);\n if (!existingUser) {\n return scimError(404, \"notFound\", \"User not found.\");\n }\n const body = await readScimJson(state.request);\n const patchData: Record<string, unknown> = {};\n let nextActive: boolean | undefined;\n if (state.request.method === \"PUT\") {\n patchData.name = body.displayName ?? body.name?.formatted;\n patchData.email =\n body.userName ??\n (Array.isArray(body.emails) ? body.emails[0]?.value : undefined);\n patchData.phone = Array.isArray(body.phoneNumbers)\n ? body.phoneNumbers[0]?.value\n : undefined;\n if (typeof patchData.email === \"string\") {\n patchData.emailVerificationTime = Date.now();\n }\n if (typeof patchData.phone === \"string\") {\n patchData.phoneVerificationTime = Date.now();\n }\n } else {\n for (const operation of Array.isArray(body.Operations)\n ? body.Operations\n : []) {\n if (operation.path === \"active\") {\n nextActive = operation.value;\n }\n if (\n operation.path === \"displayName\" ||\n operation.path === \"name.formatted\"\n ) {\n patchData.name = operation.value;\n }\n if (\n operation.path === \"userName\" ||\n operation.path === \"emails.value\"\n ) {\n patchData.email = operation.value;\n if (typeof operation.value === \"string\") {\n patchData.emailVerificationTime = Date.now();\n }\n }\n if (operation.path === \"phoneNumbers.value\") {\n patchData.phone = operation.value;\n if (typeof operation.value === \"string\") {\n patchData.phoneVerificationTime = Date.now();\n }\n }\n }\n }\n await state.ctx.runMutation(config.component.public.userPatch, {\n userId,\n data: patchData,\n });\n const resolution = await auth.member.resolve(state.ctx, {\n groupId: state.enterprise.groupId,\n userId,\n });\n if (resolution.membership) {\n await auth.member.update(state.ctx, resolution.membership._id, {\n status:\n body.active === false || nextActive === false\n ? \"inactive\"\n : \"active\",\n });\n }\n await state.ctx.runMutation(\n config.component.public.enterpriseScimIdentityUpsert,\n {\n enterpriseId: state.enterprise._id,\n groupId: state.enterprise.groupId,\n resourceType: \"user\",\n externalId:\n typeof body.externalId === \"string\"\n ? body.externalId\n : ((\n await state.ctx.runQuery(\n config.component.public\n .enterpriseScimIdentityGetByEnterpriseAndUser,\n {\n enterpriseId: state.enterprise._id,\n userId,\n },\n )\n )?.externalId ?? userId),\n userId,\n active: body.active !== false && nextActive !== false,\n raw: body,\n lastProvisionedAt: Date.now(),\n },\n );\n await state.recordScimEvent(\n \"enterprise.scim.user.updated\",\n true,\n \"user\",\n userId,\n );\n const updatedUser = await auth.user.get(state.ctx, userId);\n const location = `${state.url.origin}${state.url.pathname}`;\n return scimJson(\n serializeScimUser({\n id: userId,\n user: updatedUser ?? existingUser,\n externalId:\n typeof body.externalId === \"string\" ? body.externalId : undefined,\n location,\n active: body.active !== false && nextActive !== false,\n }),\n 200,\n { Location: location },\n );\n };\n\n const handleUsersDelete: ScimHandler = async (state) => {\n const missing = requireScimResourceId(\n state.parsedPath.resourceId,\n \"User\",\n );\n if (missing) return missing;\n const userId = state.parsedPath.resourceId!;\n const resolution = await auth.member.resolve(state.ctx, {\n groupId: state.enterprise.groupId,\n userId,\n });\n if (resolution.membership) {\n await auth.member.delete(state.ctx, resolution.membership._id);\n }\n const identity = await state.ctx.runQuery(\n config.component.public.enterpriseScimIdentityGetByEnterpriseAndUser,\n {\n enterpriseId: state.enterprise._id,\n userId,\n },\n );\n if (identity) {\n if (state.policy.provisioning.deprovision.mode === \"hard\") {\n await state.ctx.runMutation(\n config.component.public.enterpriseScimIdentityDelete,\n { identityId: identity._id },\n );\n } else {\n await state.ctx.runMutation(\n config.component.public.enterpriseScimIdentityUpsert,\n {\n enterpriseId: identity.enterpriseId,\n groupId: identity.groupId,\n resourceType: identity.resourceType,\n externalId: identity.externalId,\n userId: identity.userId,\n mappedGroupId: identity.mappedGroupId,\n active: false,\n raw: identity.raw,\n lastProvisionedAt: Date.now(),\n },\n );\n }\n }\n await state.recordScimEvent(\n \"enterprise.scim.user.deleted\",\n true,\n \"user\",\n userId,\n );\n return new Response(null, { status: 204 });\n };\n\n const handleGroupsGet: ScimHandler = async (state) => {\n const groupsList = await auth.group.list(state.ctx, {\n where: { parentGroupId: state.enterprise.groupId },\n limit: 100,\n });\n const identities = await state.ctx.runQuery(\n config.component.public.enterpriseScimIdentityListByEnterprise,\n { enterpriseId: state.enterprise._id },\n );\n const identityByGroupId = new Map(\n identities\n .filter((identity: any) => identity.mappedGroupId !== undefined)\n .map((identity: any) => [identity.mappedGroupId, identity]),\n );\n const groups = groupsList.items.map((group: any) => ({\n group,\n identity: identityByGroupId.get(group._id),\n }));\n const listRequest = parseScimListRequest(state.url);\n const filtered = filterScimCollection<{\n group: any;\n identity?: any;\n }>(groups, listRequest.filter, {\n id: (item: { group: any }, value: string) => item.group._id === value,\n externalId: (item: { identity?: any }, value: string) =>\n item.identity?.externalId === value,\n displayName: (item: { group: any }, value: string) =>\n item.group.name === value,\n });\n if (state.parsedPath.resourceId) {\n const resource = filtered.find(\n ({ group }) => group._id === state.parsedPath.resourceId,\n );\n if (!resource) {\n return scimError(404, \"notFound\", \"Group not found.\");\n }\n const members = (\n await auth.member.list(state.ctx, {\n where: {\n groupId: resource.group._id,\n status: \"active\",\n },\n limit: 100,\n })\n ).items.map((member: any) => ({ value: member.userId }));\n const location = `${state.url.origin}${state.url.pathname.replace(/\\/[^/]+$/, \"\")}/${resource.group._id}`;\n return scimJson(\n serializeScimGroup({\n id: resource.group._id,\n group: resource.group,\n externalId: resource.identity?.externalId,\n location,\n members,\n }),\n 200,\n { Location: location },\n );\n }\n const paged = paginateScimCollection(filtered, listRequest);\n return scimJson({\n schemas: [\"urn:ietf:params:scim:api:messages:2.0:ListResponse\"],\n Resources: paged.map(({ group, identity }) =>\n serializeScimGroup({\n id: group._id,\n group,\n externalId: identity?.externalId,\n location: `${state.url.origin}${state.url.pathname}/${group._id}`,\n }),\n ),\n totalResults: filtered.length,\n startIndex: listRequest.startIndex,\n itemsPerPage: paged.length,\n });\n };\n\n const handleGroupsPost: ScimHandler = async (state) => {\n const body = await readScimJson(state.request);\n const { groupId } = await auth.group.create(state.ctx, {\n name: String(body.displayName ?? \"Group\"),\n parentGroupId: state.enterprise.groupId,\n type: \"organization\",\n });\n await state.ctx.runMutation(\n config.component.public.enterpriseScimIdentityUpsert,\n {\n enterpriseId: state.enterprise._id,\n groupId: state.enterprise.groupId,\n resourceType: \"group\",\n externalId: body.externalId ?? groupId,\n mappedGroupId: groupId,\n active: true,\n raw: body,\n lastProvisionedAt: Date.now(),\n },\n );\n for (const member of Array.isArray(body.members) ? body.members : []) {\n try {\n await auth.member.create(state.ctx, {\n groupId,\n userId: String(member.value),\n roleIds: state.policy.provisioning.jit.defaultRoleIds,\n status: \"active\",\n });\n } catch {}\n }\n await state.recordScimEvent(\n \"enterprise.scim.group.created\",\n true,\n \"group\",\n groupId,\n );\n const group = await auth.group.get(state.ctx, groupId);\n const location = `${state.url.origin}${state.url.pathname}/${groupId}`;\n return scimJson(\n serializeScimGroup({\n id: groupId,\n group: group ?? {},\n externalId: body.externalId,\n location,\n members: (\n await auth.member.list(state.ctx, {\n where: { groupId, status: \"active\" },\n limit: 100,\n })\n ).items.map((member: any) => ({ value: member.userId })),\n }),\n 201,\n { Location: location },\n );\n };\n\n const handleGroupsPatch: ScimHandler = async (state) => {\n const missing = requireScimResourceId(\n state.parsedPath.resourceId,\n \"Group\",\n );\n if (missing) return missing;\n const groupId = state.parsedPath.resourceId!;\n const body = await readScimJson(state.request);\n for (const operation of Array.isArray(body.Operations)\n ? body.Operations\n : []) {\n if (operation.path === \"displayName\") {\n await auth.group.update(state.ctx, groupId, {\n name: operation.value,\n });\n }\n if (operation.path === \"members\" && operation.op === \"add\") {\n for (const member of Array.isArray(operation.value)\n ? operation.value\n : []) {\n try {\n await auth.member.create(state.ctx, {\n groupId,\n userId: String(member.value),\n roleIds: state.policy.provisioning.jit.defaultRoleIds,\n status: \"active\",\n });\n } catch {}\n }\n }\n if (operation.path === \"members\" && operation.op === \"replace\") {\n const currentMembers = (\n await auth.member.list(state.ctx, {\n where: { groupId, status: \"active\" },\n limit: 100,\n })\n ).items as Array<{ _id: string; userId: string }>;\n const currentUserIds = new Set<string>(\n currentMembers.map((member) => member.userId),\n );\n const nextUserIds = new Set<string>(\n (Array.isArray(operation.value) ? operation.value : []).map(\n (member: any) => String(member.value),\n ),\n );\n for (const member of currentMembers) {\n if (!nextUserIds.has(member.userId)) {\n await auth.member.delete(state.ctx, member._id);\n }\n }\n for (const userId of nextUserIds.values()) {\n if (!currentUserIds.has(userId)) {\n try {\n await auth.member.create(state.ctx, {\n groupId,\n userId,\n roleIds: state.policy.provisioning.jit.defaultRoleIds,\n status: \"active\",\n });\n } catch {}\n }\n }\n }\n if (\n typeof operation.path === \"string\" &&\n operation.op === \"remove\" &&\n operation.path.startsWith(\"members[\")\n ) {\n const match = operation.path.match(\n /^members\\[value eq \"([^\"]+)\"\\]$/,\n );\n const userId = match?.[1];\n if (userId) {\n const resolution = await auth.member.resolve(\n state.ctx,\n { groupId, userId },\n );\n if (resolution.membership) {\n await auth.member.delete(\n state.ctx,\n resolution.membership._id,\n );\n }\n }\n }\n }\n await state.recordScimEvent(\n \"enterprise.scim.group.updated\",\n true,\n \"group\",\n groupId,\n );\n const group = await auth.group.get(state.ctx, groupId);\n const location = `${state.url.origin}${state.url.pathname}`;\n const members = (\n await auth.member.list(state.ctx, {\n where: { groupId, status: \"active\" },\n limit: 100,\n })\n ).items as Array<{ userId: string }>;\n return scimJson(\n serializeScimGroup({\n id: groupId,\n group: group ?? {},\n location,\n members: members.map((member) => ({\n value: member.userId,\n })),\n }),\n 200,\n { Location: location },\n );\n };\n\n const handleGroupsDelete: ScimHandler = async (state) => {\n const missing = requireScimResourceId(\n state.parsedPath.resourceId,\n \"Group\",\n );\n if (missing) return missing;\n const groupId = state.parsedPath.resourceId!;\n await auth.group.delete(state.ctx, groupId);\n const identity = await state.ctx.runQuery(\n config.component.public.enterpriseScimIdentityGetByMappedGroup,\n { mappedGroupId: groupId },\n );\n if (identity) {\n await state.ctx.runMutation(\n config.component.public.enterpriseScimIdentityDelete,\n { identityId: identity._id },\n );\n }\n await state.recordScimEvent(\n \"enterprise.scim.group.deleted\",\n true,\n \"group\",\n groupId,\n );\n return new Response(null, { status: 204 });\n };\n\n const scimHandlers: Record<\n string,\n Partial<Record<string, ScimHandler>>\n > = {\n ServiceProviderConfig: {\n GET: async () =>\n scimJson({\n schemas: [\n \"urn:ietf:params:scim:schemas:core:2.0:ServiceProviderConfig\",\n ],\n patch: { supported: true },\n bulk: {\n supported: false,\n maxOperations: 0,\n maxPayloadSize: 0,\n },\n filter: { supported: true, maxResults: 100 },\n changePassword: { supported: false },\n sort: { supported: false },\n etag: { supported: false },\n authenticationSchemes: [\n {\n type: \"oauthbearertoken\",\n name: \"Bearer Token\",\n description:\n \"Use the SCIM token generated by Convex Auth enterprise.\",\n },\n ],\n }),\n },\n Schemas: {\n GET: async (state) =>\n handleStaticScimCollection(\n SCIM_SCHEMAS,\n state.parsedPath.resourceId,\n {\n by: \"id\",\n notFound: \"Schema not found.\",\n },\n ),\n },\n ResourceTypes: {\n GET: async (state) =>\n handleStaticScimCollection(\n SCIM_RESOURCE_TYPES,\n state.parsedPath.resourceId,\n { by: \"name\", notFound: \"Resource type not found.\" },\n ),\n },\n Users: {\n GET: handleUsersGet,\n POST: handleUsersPost,\n PATCH: handleUsersUpsert,\n PUT: handleUsersUpsert,\n DELETE: handleUsersDelete,\n },\n Groups: {\n GET: handleGroupsGet,\n POST: handleGroupsPost,\n PATCH: handleGroupsPatch,\n DELETE: handleGroupsDelete,\n },\n };\n\n const handler =\n scimHandlers[state.parsedPath.resource]?.[state.request.method];\n return handler\n ? await handler(state)\n : scimError(404, \"notFound\", \"SCIM resource not found.\");\n } catch (error) {\n if (\n error instanceof Error &&\n error.message === \"Unsupported SCIM filter.\"\n ) {\n return scimError(400, \"invalidFilter\", error.message);\n }\n if (isAuthError(error)) {\n const code = error.data.code as string;\n const status =\n code === \"MISSING_BEARER_TOKEN\" || code === \"INVALID_API_KEY\"\n ? 401\n : 400;\n return scimError(status, code, error.data.message);\n }\n throw error;\n }\n };\n\n addSSORoutes(http, {\n routeBase: ENTERPRISE_CONTROL_ROUTE_BASE,\n convertErrorsToResponse,\n handleSamlMetadata: async (ctx, _request, runtimeRoute) => {\n const { loaded } = await loadActiveEnterpriseSamlOrThrow(\n ctx,\n runtimeRoute.enterpriseId,\n );\n return new Response(\n createEnterpriseSamlMetadataXml({\n rootUrl: requireEnv(\"CONVEX_SITE_URL\"),\n source: loaded.source,\n config: loaded.config,\n }),\n {\n status: 200,\n headers: { \"Content-Type\": \"application/xml\" },\n },\n );\n },\n handleSamlSignIn: async (ctx, request, runtimeRoute) => {\n const url = new URL(request.url);\n const verifier = url.searchParams.get(\"code\");\n if (!verifier) {\n throw new AuthError(\"OAUTH_MISSING_VERIFIER\").toConvexError();\n }\n const { loaded, enterprise } = await loadActiveEnterpriseSamlOrThrow(\n ctx,\n runtimeRoute.enterpriseId,\n );\n const state = generateRandomString(24, INVITE_TOKEN_ALPHABET);\n const signInRequest = createEnterpriseSamlSignInRequest({\n rootUrl: requireEnv(\"CONVEX_SITE_URL\"),\n source: { kind: \"enterprise\", id: enterprise._id },\n config: loaded.config,\n state,\n signature: `saml ${enterprise._id} pending ${state}`,\n redirectTo: url.searchParams.get(\"redirectTo\") ?? undefined,\n });\n const signature = `saml ${enterprise._id} ${signInRequest.requestId} ${state}`;\n await callVerifierSignature(ctx, { verifier, signature });\n const redirectTo = url.searchParams.get(\"redirectTo\");\n const redirectCookies =\n redirectTo !== null\n ? [\n redirectToParamCookie(\n enterpriseSamlProviderId(enterprise._id),\n redirectTo,\n ),\n ]\n : [];\n const relayState = encodeEnterpriseSamlRelayState({\n source: { kind: \"enterprise\", id: enterprise._id },\n signature,\n requestId: signInRequest.requestId,\n state,\n redirectTo: url.searchParams.get(\"redirectTo\") ?? undefined,\n });\n if (signInRequest.binding === \"redirect\" && signInRequest.redirectUrl) {\n const redirectUrl = new URL(signInRequest.redirectUrl);\n redirectUrl.searchParams.set(\"RelayState\", relayState);\n const headers = new Headers({\n Location: redirectUrl.toString(),\n });\n for (const { name, value, options } of redirectCookies as any) {\n headers.append(\"Set-Cookie\", serializeCookie(name, value, options));\n }\n return new Response(null, { status: 302, headers });\n }\n const response = createSamlPostBindingResponse({\n endpoint: signInRequest.post!.endpoint,\n parameter: \"SAMLRequest\",\n value: signInRequest.post!.value,\n relayState,\n });\n for (const { name, value, options } of redirectCookies as any) {\n response.headers.append(\n \"Set-Cookie\",\n serializeCookie(name, value, options),\n );\n }\n return response;\n },\n handleOidcSignIn: async (ctx, request, runtimeRoute) => {\n const url = new URL(request.url);\n const verifier = url.searchParams.get(\"code\");\n if (!verifier) {\n throw new AuthError(\"OAUTH_MISSING_VERIFIER\").toConvexError();\n }\n const { enterprise, oidc } = await loadEnterpriseOidcOrThrow(\n ctx,\n runtimeRoute.enterpriseId,\n );\n const { providerId, provider, oauthConfig } =\n await createEnterpriseOidcRuntime({\n rootUrl: requireEnv(\"CONVEX_SITE_URL\"),\n enterpriseId: enterprise._id,\n oidc,\n });\n const { redirect, cookies, signature } =\n await createOAuthAuthorizationURL(providerId, provider, oauthConfig);\n await callVerifierSignature(ctx, { verifier, signature });\n const redirectTo = url.searchParams.get(\"redirectTo\");\n const headers_ = new Headers({ Location: redirect });\n for (const { name, value, options } of [\n ...cookies,\n ...(redirectTo !== null\n ? [redirectToParamCookie(providerId, redirectTo)]\n : []),\n ] as any) {\n headers_.append(\"Set-Cookie\", serializeCookie(name, value, options));\n }\n return new Response(null, {\n status: 302,\n headers: headers_,\n });\n },\n handleOidcCallback: async (ctx, request, runtimeRoute) => {\n const url = new URL(request.url);\n const { enterprise, oidc } = await loadEnterpriseOidcOrThrow(\n ctx,\n runtimeRoute.enterpriseId,\n );\n const { providerId, provider, oauthConfig } =\n await createEnterpriseOidcRuntime({\n rootUrl: requireEnv(\"CONVEX_SITE_URL\"),\n enterpriseId: enterprise._id,\n oidc,\n });\n const cookies = getCookies(request);\n const maybeRedirectTo = useRedirectToParam(providerId, cookies);\n const destinationUrl = await redirectAbsoluteUrl(config, {\n redirectTo: maybeRedirectTo?.redirectTo,\n });\n const params = url.searchParams;\n const result = (await Fx.run(\n handleOAuthCallback(\n providerId,\n provider,\n oauthConfig,\n Object.fromEntries(params.entries()),\n cookies,\n ),\n )) as any;\n const extraFields = oidc.extraFields as\n | Record<string, string>\n | undefined;\n let profile = result.profile as Record<string, unknown>;\n if (extraFields && typeof profile === \"object\" && profile) {\n const extend: Record<string, unknown> = {};\n for (const [claimName, fieldName] of Object.entries(extraFields)) {\n if (claimName in profile) {\n extend[fieldName] = profile[claimName];\n }\n }\n if (Object.keys(extend).length > 0) {\n profile = { ...profile, extend };\n }\n }\n\n const verificationCode = await callUserOAuth(ctx, {\n provider: providerId,\n providerAccountId: result.providerAccountId,\n profile,\n signature: result.signature,\n accountExtend: {\n identity: {\n protocol: \"oidc\",\n enterpriseId: enterprise._id,\n subject: result.providerAccountId,\n issuer: typeof oidc.issuer === \"string\" ? oidc.issuer : undefined,\n discoveryUrl:\n typeof oidc.discoveryUrl === \"string\"\n ? oidc.discoveryUrl\n : undefined,\n },\n },\n });\n const headers = new Headers({\n Location: setURLSearchParam(destinationUrl, \"code\", verificationCode),\n });\n for (const { name, value, options } of result.cookies) {\n headers.append(\n \"Set-Cookie\",\n serializeCookie(name, value, options as any),\n );\n }\n if (maybeRedirectTo) {\n headers.append(\n \"Set-Cookie\",\n serializeCookie(\n maybeRedirectTo.updatedCookie.name,\n maybeRedirectTo.updatedCookie.value,\n maybeRedirectTo.updatedCookie.options as any,\n ),\n );\n }\n return new Response(null, { status: 302, headers });\n },\n handleSamlAcs,\n handleSamlSlo,\n handleScimRequest,\n scimError,\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"http.js","names":["serializeCookie","state"],"sources":["../../../src/server/enterprise/http.ts"],"sourcesContent":["import { Fx } from \"@robelest/fx\";\nimport { Cv } from \"@robelest/fx/convex\";\nimport type { GenericActionCtx, HttpRouter } from \"convex/server\";\nimport { ConvexError } from \"convex/values\";\nimport { serialize as serializeCookie } from \"cookie\";\n\nimport { redirectToParamCookie, useRedirectToParam } from \"../cookies\";\nimport { addSSORoutes, convertErrorsToResponse, getCookies } from \"../http\";\nimport type { SSORuntimeRoute } from \"../http\";\nimport { createOAuthAuthorizationURL, handleOAuthCallback } from \"../oauth\";\nimport { redirectAbsoluteUrl, setURLSearchParam } from \"../redirects\";\nimport { createEnterpriseOidcRuntime } from \"./oidc\";\nimport {\n createEnterpriseSamlMetadataXml,\n createEnterpriseSamlSignInRequest,\n createSamlPostBindingResponse,\n encodeEnterpriseSamlRelayState,\n parseEnterpriseSamlLoginResponse,\n parseEnterpriseSamlLogoutMessage,\n profileFromSamlExtract,\n validateEnterpriseSamlLoginRelayState,\n} from \"./saml\";\nimport {\n parseScimListRequest,\n scimError,\n scimJson,\n serializeScimGroup,\n serializeScimUser,\n} from \"./scim\";\nimport {\n enterpriseSamlProviderId,\n SCIM_GROUP_SCHEMA_ID,\n SCIM_USER_SCHEMA_ID,\n} from \"./shared\";\n\nexport type EnterpriseHttpRuntimeDeps = {\n http: HttpRouter;\n hasSSO: boolean;\n auth: any;\n config: any;\n routeBase: string;\n requireEnv: (name: string) => string;\n loadActiveEnterpriseSamlOrThrow: any;\n loadEnterpriseOidcOrThrow: any;\n getEnterpriseScimContext: any;\n getPolicyFromEnterprise: any;\n normalizeEnterprisePolicy: any;\n recordEnterpriseAuditEvent: any;\n emitEnterpriseWebhookDeliveries: any;\n generateRandomString: (length: number, alphabet: string) => string;\n inviteTokenAlphabet: string;\n callUserOAuth: any;\n callVerifierSignature: any;\n};\n\nexport function addEnterpriseHttpRuntime(deps: EnterpriseHttpRuntimeDeps) {\n if (!deps.hasSSO) {\n return;\n }\n\n const {\n http,\n auth,\n config,\n requireEnv,\n loadActiveEnterpriseSamlOrThrow,\n loadEnterpriseOidcOrThrow,\n getEnterpriseScimContext,\n getPolicyFromEnterprise,\n recordEnterpriseAuditEvent,\n emitEnterpriseWebhookDeliveries,\n generateRandomString,\n inviteTokenAlphabet: INVITE_TOKEN_ALPHABET,\n callUserOAuth,\n callVerifierSignature,\n } = deps;\n const ENTERPRISE_CONTROL_ROUTE_BASE = deps.routeBase;\n\n type ScimState = {\n ctx: any;\n request: Request;\n url: URL;\n parsedPath: Awaited<\n ReturnType<typeof getEnterpriseScimContext>\n >[\"parsedPath\"];\n enterprise: Awaited<\n ReturnType<typeof getEnterpriseScimContext>\n >[\"enterprise\"];\n scimConfig: Awaited<\n ReturnType<typeof getEnterpriseScimContext>\n >[\"scimConfig\"];\n policy: any;\n recordScimEvent: (\n eventType: string,\n ok: boolean,\n subjectType: string,\n subjectId?: string,\n metadata?: Record<string, unknown>,\n ) => Promise<void>;\n };\n\n type ScimHandler = (state: ScimState) => Promise<Response>;\n\n const SCIM_SCHEMAS = [\n {\n id: SCIM_USER_SCHEMA_ID,\n name: \"User\",\n description: \"User Account\",\n attributes: [\n { name: \"userName\", type: \"string\", required: true },\n { name: \"displayName\", type: \"string\" },\n { name: \"active\", type: \"boolean\" },\n { name: \"emails\", type: \"complex\", multiValued: true },\n ],\n },\n {\n id: SCIM_GROUP_SCHEMA_ID,\n name: \"Group\",\n description: \"Group\",\n attributes: [\n { name: \"displayName\", type: \"string\", required: true },\n { name: \"members\", type: \"complex\", multiValued: true },\n ],\n },\n ] as const;\n\n const SCIM_RESOURCE_TYPES = [\n {\n id: \"User\",\n name: \"User\",\n endpoint: \"/Users\",\n schema: SCIM_USER_SCHEMA_ID,\n },\n {\n id: \"Group\",\n name: \"Group\",\n endpoint: \"/Groups\",\n schema: SCIM_GROUP_SCHEMA_ID,\n },\n ] as const;\n\n const handleStaticScimCollection = <T extends { id?: string; name?: string }>(\n items: readonly T[],\n resourceId: string | undefined,\n opts: { by: \"id\" | \"name\"; notFound: string },\n ) => {\n if (resourceId !== undefined) {\n const item = items.find(\n (entry) => entry[opts.by] === decodeURIComponent(resourceId),\n );\n return item ? scimJson(item) : scimError(404, \"notFound\", opts.notFound);\n }\n return scimJson({\n schemas: [\"urn:ietf:params:scim:api:messages:2.0:ListResponse\"],\n Resources: items,\n totalResults: items.length,\n startIndex: 1,\n itemsPerPage: items.length,\n });\n };\n\n const filterScimCollection = <T>(\n items: T[],\n filter: ReturnType<typeof parseScimListRequest>[\"filter\"],\n filters: Record<string, (item: T, value: string) => boolean>,\n ) => {\n if (!filter) {\n return items;\n }\n const predicate = filters[filter.attribute];\n if (!predicate) {\n throw new Error(\"Unsupported SCIM filter.\");\n }\n return items.filter((item) => predicate(item, filter.value));\n };\n\n const paginateScimCollection = <T>(\n items: T[],\n listRequest: ReturnType<typeof parseScimListRequest>,\n ) => {\n const start = listRequest.startIndex - 1;\n return items.slice(start, start + listRequest.count);\n };\n\n const requireScimResourceId = (\n resourceId: string | undefined,\n label: string,\n ) => {\n if (!resourceId) {\n return scimError(400, \"invalidPath\", `${label} resource ID is required.`);\n }\n return null;\n };\n\n const readScimJson = async (request: Request) =>\n (await request.json()) as Record<string, any>;\n\n const handleSamlAcs = async (\n ctx: GenericActionCtx<any>,\n request: Request,\n runtimeRoute: SSORuntimeRoute,\n ) =>\n Fx.run(\n Fx.gen(function* () {\n yield* Fx.guard(\n runtimeRoute.protocol !== \"saml\" ||\n runtimeRoute.rest.length !== 1 ||\n runtimeRoute.rest[0] !== \"acs\",\n Cv.fail({\n code: \"INVALID_PARAMETERS\",\n message: \"Invalid enterprise runtime path.\",\n }),\n );\n\n const enterpriseId = runtimeRoute.enterpriseId;\n const { loaded, enterprise, saml } = yield* Fx.from({\n ok: () => loadActiveEnterpriseSamlOrThrow(ctx, enterpriseId),\n err: (e) => e,\n });\n\n const parsedResponse = yield* Fx.from({\n ok: () =>\n parseEnterpriseSamlLoginResponse({\n request,\n rootUrl: requireEnv(\"CONVEX_SITE_URL\"),\n source: { kind: \"enterprise\", id: enterprise._id },\n config: loaded.config,\n }),\n err: (e) =>\n Cv.error({\n code: \"OAUTH_PROVIDER_ERROR\",\n message: `SAML response parse failed: ${e instanceof Error ? e.message : String(e)}`,\n }),\n });\n\n yield* Fx.from({\n ok: () => {\n validateEnterpriseSamlLoginRelayState({\n relayState: parsedResponse.relayState,\n source: { kind: \"enterprise\", id: enterprise._id },\n inResponseTo:\n parsedResponse.parsed.extract?.response?.inResponseTo,\n });\n return Promise.resolve();\n },\n err: () =>\n Cv.error({\n code: \"OAUTH_INVALID_STATE\",\n message:\n \"SAML RelayState did not match the pending login request.\",\n }),\n });\n\n const { samlAttributes, samlSessionIndex, ...userProfile } =\n profileFromSamlExtract(\n parsedResponse.parsed.extract,\n saml.attributeMapping,\n );\n const profile = userProfile as Record<string, unknown> & {\n id: string;\n };\n\n const maybeRedirectTo = useRedirectToParam(\n enterpriseSamlProviderId(enterprise._id),\n getCookies(request),\n );\n\n const verificationCode = yield* Fx.from({\n ok: () =>\n callUserOAuth(ctx, {\n provider: enterpriseSamlProviderId(enterprise._id),\n providerAccountId: profile.id,\n profile,\n signature: parsedResponse.relayState.signature,\n accountExtend: {\n identity: {\n protocol: \"saml\",\n enterpriseId: enterprise._id,\n subject: profile.id,\n entityId:\n typeof saml.entityId === \"string\"\n ? saml.entityId\n : undefined,\n },\n saml: {\n attributes: samlAttributes,\n sessionIndex: samlSessionIndex,\n },\n },\n }),\n err: (e) => e,\n });\n\n const destinationUrl = yield* Fx.from({\n ok: () =>\n redirectAbsoluteUrl(config, {\n redirectTo:\n maybeRedirectTo?.redirectTo ??\n (typeof parsedResponse.relayState.redirectTo === \"string\"\n ? parsedResponse.relayState.redirectTo\n : undefined),\n }),\n err: (e) => e,\n });\n\n const vurl = setURLSearchParam(\n destinationUrl,\n \"code\",\n verificationCode,\n );\n const vheaders = new Headers({ Location: vurl });\n vheaders.set(\"Cache-Control\", \"must-revalidate\");\n for (const { name, value, options } of maybeRedirectTo !== null\n ? [maybeRedirectTo.updatedCookie]\n : []) {\n vheaders.append(\"Set-Cookie\", serializeCookie(name, value, options));\n }\n return new Response(null, { status: 302, headers: vheaders });\n }).pipe(Fx.recover((e) => Fx.fatal(e))),\n );\n\n const handleSamlSlo = async (\n ctx: GenericActionCtx<any>,\n request: Request,\n runtimeRoute: SSORuntimeRoute,\n ) => {\n if (\n runtimeRoute.protocol !== \"saml\" ||\n runtimeRoute.rest.length !== 1 ||\n runtimeRoute.rest[0] !== \"slo\"\n ) {\n throw Cv.error({\n code: \"INVALID_PARAMETERS\",\n message: \"Invalid enterprise runtime path.\",\n });\n }\n const { loaded, enterprise } = await loadActiveEnterpriseSamlOrThrow(\n ctx,\n runtimeRoute.enterpriseId,\n );\n const parsedMessage = await parseEnterpriseSamlLogoutMessage({\n request,\n rootUrl: requireEnv(\"CONVEX_SITE_URL\"),\n source: { kind: \"enterprise\", id: enterprise._id },\n config: loaded.config,\n });\n if (parsedMessage.hasSamlRequest && parsedMessage.parsedRequest) {\n const responseContext = (\n parsedMessage.runtime.sp as any\n ).createLogoutResponse(\n parsedMessage.runtime.idp as any,\n parsedMessage.parsedRequest.extract,\n parsedMessage.binding as any,\n parsedMessage.relayState ?? \"\",\n ) as any;\n if (parsedMessage.binding === \"redirect\") {\n return new Response(null, {\n status: 302,\n headers: { Location: responseContext.context },\n });\n }\n return createSamlPostBindingResponse({\n endpoint: responseContext.entityEndpoint,\n parameter: \"SAMLResponse\",\n value: responseContext.context,\n relayState: parsedMessage.relayState,\n });\n }\n if (parsedMessage.hasSamlResponse) {\n return new Response(null, { status: 204 });\n }\n throw Cv.error({\n code: \"INVALID_PARAMETERS\",\n message: \"Missing SAML logout payload.\",\n });\n };\n\n const handleScimRequest = async (\n ctx: GenericActionCtx<any>,\n request: Request,\n ) => {\n try {\n const { scimConfig, enterprise, parsedPath } =\n await getEnterpriseScimContext(ctx, request);\n const url = new URL(request.url);\n const state: ScimState = {\n ctx,\n request,\n url,\n parsedPath,\n enterprise,\n scimConfig,\n policy: getPolicyFromEnterprise(enterprise),\n recordScimEvent: async (\n eventType,\n ok,\n subjectType,\n subjectId,\n metadata,\n ) => {\n const auditEventId = await recordEnterpriseAuditEvent(ctx, {\n enterpriseId: enterprise._id,\n groupId: enterprise.groupId,\n eventType,\n actorType: \"scim\",\n subjectType,\n subjectId,\n ok,\n metadata,\n });\n await emitEnterpriseWebhookDeliveries(ctx, {\n enterpriseId: enterprise._id,\n eventType,\n auditEventId,\n payload: {\n enterpriseId: enterprise._id,\n subjectId,\n metadata,\n },\n });\n },\n };\n\n const handleUsersGet: ScimHandler = async (state) => {\n const members = await auth.member.list(state.ctx, {\n where: { groupId: state.enterprise.groupId },\n limit: 100,\n });\n const identities = await state.ctx.runQuery(\n config.component.public.enterpriseScimIdentityListByEnterprise,\n { enterpriseId: state.enterprise._id },\n );\n const identityByUserId = new Map(\n identities\n .filter((identity: any) => identity.userId !== undefined)\n .map((identity: any) => [identity.userId, identity]),\n );\n const users = (\n await Promise.all(\n members.items.map(async (member: any) => {\n const user = await auth.user.get(state.ctx, member.userId);\n return user\n ? {\n user,\n member,\n identity: identityByUserId.get(user._id),\n }\n : null;\n }),\n )\n ).filter(Boolean) as Array<{\n user: any;\n member: any;\n identity?: any;\n }>;\n const listRequest = parseScimListRequest(state.url);\n const filtered = filterScimCollection(users, listRequest.filter, {\n id: (item: { user: any }, value: string) => item.user._id === value,\n externalId: (item: { identity?: any }, value: string) =>\n item.identity?.externalId === value,\n userName: (item: { user: any }, value: string) =>\n item.user.email === value,\n \"emails.value\": (item: { user: any }, value: string) =>\n item.user.email === value,\n active: (item: { identity?: any; member: any }, value: string) =>\n String(item.identity?.active ?? item.member.status === \"active\") ===\n value,\n });\n if (state.parsedPath.resourceId) {\n const resource = filtered.find(\n ({ user }) => user._id === state.parsedPath.resourceId,\n );\n return resource\n ? scimJson(\n serializeScimUser({\n id: resource.user._id,\n user: resource.user,\n externalId: resource.identity?.externalId,\n location: `${state.url.origin}${state.url.pathname.replace(/\\/[^/]+$/, \"\")}/${resource.user._id}`,\n active:\n resource.identity?.active ??\n resource.member.status === \"active\",\n }),\n 200,\n {\n Location: `${state.url.origin}${state.url.pathname.replace(/\\/[^/]+$/, \"\")}/${resource.user._id}`,\n },\n )\n : scimError(404, \"notFound\", \"User not found.\");\n }\n const paged = paginateScimCollection(filtered, listRequest);\n await state.recordScimEvent(\n \"enterprise.scim.read\",\n true,\n \"enterprise_scim\",\n state.scimConfig._id,\n );\n return scimJson({\n schemas: [\"urn:ietf:params:scim:api:messages:2.0:ListResponse\"],\n Resources: paged.map(({ user, identity, member }) =>\n serializeScimUser({\n id: user._id,\n user,\n externalId: identity?.externalId,\n location: `${state.url.origin}${state.url.pathname}/${user._id}`,\n active: identity?.active ?? member.status === \"active\",\n }),\n ),\n totalResults: filtered.length,\n startIndex: listRequest.startIndex,\n itemsPerPage: paged.length,\n });\n };\n\n const handleUsersPost: ScimHandler = async (state) => {\n const body = await readScimJson(state.request);\n const primaryEmail = Array.isArray(body.emails)\n ? (body.emails.find((entry) => entry.primary === true)?.value ??\n body.emails[0]?.value)\n : undefined;\n const phone = Array.isArray(body.phoneNumbers)\n ? body.phoneNumbers[0]?.value\n : undefined;\n const userId = (await state.ctx.runMutation(\n config.component.public.userInsert,\n {\n data: {\n name: body.displayName ?? body.name?.formatted,\n email: primaryEmail ?? body.userName,\n ...(typeof (primaryEmail ?? body.userName) === \"string\"\n ? { emailVerificationTime: Date.now() }\n : {}),\n phone,\n ...(typeof phone === \"string\"\n ? { phoneVerificationTime: Date.now() }\n : {}),\n },\n },\n )) as string;\n try {\n await auth.member.create(state.ctx, {\n groupId: state.enterprise.groupId,\n userId,\n roleIds: state.policy.provisioning.jit.defaultRoleIds,\n status: body.active === false ? \"inactive\" : \"active\",\n });\n } catch {}\n if (typeof body.externalId === \"string\") {\n await state.ctx.runMutation(\n config.component.public.enterpriseScimIdentityUpsert,\n {\n enterpriseId: state.enterprise._id,\n groupId: state.enterprise.groupId,\n resourceType: \"user\",\n externalId: body.externalId,\n userId,\n active: body.active !== false,\n raw: body,\n lastProvisionedAt: Date.now(),\n },\n );\n }\n await state.recordScimEvent(\n \"enterprise.scim.user.created\",\n true,\n \"user\",\n userId,\n );\n const createdUser = await auth.user.get(state.ctx, userId);\n const location = `${state.url.origin}${state.url.pathname}/${userId}`;\n return scimJson(\n serializeScimUser({\n id: userId,\n user: createdUser ?? {},\n externalId: body.externalId,\n location,\n active: body.active !== false,\n }),\n 201,\n { Location: location },\n );\n };\n\n const handleUsersUpsert: ScimHandler = async (state) => {\n const missing = requireScimResourceId(\n state.parsedPath.resourceId,\n \"User\",\n );\n if (missing) return missing;\n const userId = state.parsedPath.resourceId!;\n const existingUser = await auth.user.get(state.ctx, userId);\n if (!existingUser) {\n return scimError(404, \"notFound\", \"User not found.\");\n }\n const body = await readScimJson(state.request);\n const patchData: Record<string, unknown> = {};\n let nextActive: boolean | undefined;\n if (state.request.method === \"PUT\") {\n patchData.name = body.displayName ?? body.name?.formatted;\n patchData.email =\n body.userName ??\n (Array.isArray(body.emails) ? body.emails[0]?.value : undefined);\n patchData.phone = Array.isArray(body.phoneNumbers)\n ? body.phoneNumbers[0]?.value\n : undefined;\n if (typeof patchData.email === \"string\") {\n patchData.emailVerificationTime = Date.now();\n }\n if (typeof patchData.phone === \"string\") {\n patchData.phoneVerificationTime = Date.now();\n }\n } else {\n for (const operation of Array.isArray(body.Operations)\n ? body.Operations\n : []) {\n if (operation.path === \"active\") {\n nextActive = operation.value;\n }\n if (\n operation.path === \"displayName\" ||\n operation.path === \"name.formatted\"\n ) {\n patchData.name = operation.value;\n }\n if (\n operation.path === \"userName\" ||\n operation.path === \"emails.value\"\n ) {\n patchData.email = operation.value;\n if (typeof operation.value === \"string\") {\n patchData.emailVerificationTime = Date.now();\n }\n }\n if (operation.path === \"phoneNumbers.value\") {\n patchData.phone = operation.value;\n if (typeof operation.value === \"string\") {\n patchData.phoneVerificationTime = Date.now();\n }\n }\n }\n }\n await state.ctx.runMutation(config.component.public.userPatch, {\n userId,\n data: patchData,\n });\n const resolution = await auth.member.inspect(state.ctx, {\n groupId: state.enterprise.groupId,\n userId,\n });\n if (resolution.membership) {\n await auth.member.update(state.ctx, resolution.membership._id, {\n status:\n body.active === false || nextActive === false\n ? \"inactive\"\n : \"active\",\n });\n }\n await state.ctx.runMutation(\n config.component.public.enterpriseScimIdentityUpsert,\n {\n enterpriseId: state.enterprise._id,\n groupId: state.enterprise.groupId,\n resourceType: \"user\",\n externalId:\n typeof body.externalId === \"string\"\n ? body.externalId\n : ((\n await state.ctx.runQuery(\n config.component.public\n .enterpriseScimIdentityGetByEnterpriseAndUser,\n {\n enterpriseId: state.enterprise._id,\n userId,\n },\n )\n )?.externalId ?? userId),\n userId,\n active: body.active !== false && nextActive !== false,\n raw: body,\n lastProvisionedAt: Date.now(),\n },\n );\n await state.recordScimEvent(\n \"enterprise.scim.user.updated\",\n true,\n \"user\",\n userId,\n );\n const updatedUser = await auth.user.get(state.ctx, userId);\n const location = `${state.url.origin}${state.url.pathname}`;\n return scimJson(\n serializeScimUser({\n id: userId,\n user: updatedUser ?? existingUser,\n externalId:\n typeof body.externalId === \"string\" ? body.externalId : undefined,\n location,\n active: body.active !== false && nextActive !== false,\n }),\n 200,\n { Location: location },\n );\n };\n\n const handleUsersDelete: ScimHandler = async (state) => {\n const missing = requireScimResourceId(\n state.parsedPath.resourceId,\n \"User\",\n );\n if (missing) return missing;\n const userId = state.parsedPath.resourceId!;\n const resolution = await auth.member.inspect(state.ctx, {\n groupId: state.enterprise.groupId,\n userId,\n });\n if (resolution.membership) {\n await auth.member.delete(state.ctx, resolution.membership._id);\n }\n const identity = await state.ctx.runQuery(\n config.component.public.enterpriseScimIdentityGetByEnterpriseAndUser,\n {\n enterpriseId: state.enterprise._id,\n userId,\n },\n );\n if (identity) {\n if (state.policy.provisioning.deprovision.mode === \"hard\") {\n await state.ctx.runMutation(\n config.component.public.enterpriseScimIdentityDelete,\n { identityId: identity._id },\n );\n } else {\n await state.ctx.runMutation(\n config.component.public.enterpriseScimIdentityUpsert,\n {\n enterpriseId: identity.enterpriseId,\n groupId: identity.groupId,\n resourceType: identity.resourceType,\n externalId: identity.externalId,\n userId: identity.userId,\n mappedGroupId: identity.mappedGroupId,\n active: false,\n raw: identity.raw,\n lastProvisionedAt: Date.now(),\n },\n );\n }\n }\n await state.recordScimEvent(\n \"enterprise.scim.user.deleted\",\n true,\n \"user\",\n userId,\n );\n return new Response(null, { status: 204 });\n };\n\n const handleGroupsGet: ScimHandler = async (state) => {\n const groupsList = await auth.group.list(state.ctx, {\n where: { parentGroupId: state.enterprise.groupId },\n limit: 100,\n });\n const identities = await state.ctx.runQuery(\n config.component.public.enterpriseScimIdentityListByEnterprise,\n { enterpriseId: state.enterprise._id },\n );\n const identityByGroupId = new Map(\n identities\n .filter((identity: any) => identity.mappedGroupId !== undefined)\n .map((identity: any) => [identity.mappedGroupId, identity]),\n );\n const groups = groupsList.items.map((group: any) => ({\n group,\n identity: identityByGroupId.get(group._id),\n }));\n const listRequest = parseScimListRequest(state.url);\n const filtered = filterScimCollection<{\n group: any;\n identity?: any;\n }>(groups, listRequest.filter, {\n id: (item: { group: any }, value: string) => item.group._id === value,\n externalId: (item: { identity?: any }, value: string) =>\n item.identity?.externalId === value,\n displayName: (item: { group: any }, value: string) =>\n item.group.name === value,\n });\n if (state.parsedPath.resourceId) {\n const resource = filtered.find(\n ({ group }) => group._id === state.parsedPath.resourceId,\n );\n if (!resource) {\n return scimError(404, \"notFound\", \"Group not found.\");\n }\n const members = (\n await auth.member.list(state.ctx, {\n where: {\n groupId: resource.group._id,\n status: \"active\",\n },\n limit: 100,\n })\n ).items.map((member: any) => ({ value: member.userId }));\n const location = `${state.url.origin}${state.url.pathname.replace(/\\/[^/]+$/, \"\")}/${resource.group._id}`;\n return scimJson(\n serializeScimGroup({\n id: resource.group._id,\n group: resource.group,\n externalId: resource.identity?.externalId,\n location,\n members,\n }),\n 200,\n { Location: location },\n );\n }\n const paged = paginateScimCollection(filtered, listRequest);\n return scimJson({\n schemas: [\"urn:ietf:params:scim:api:messages:2.0:ListResponse\"],\n Resources: paged.map(({ group, identity }) =>\n serializeScimGroup({\n id: group._id,\n group,\n externalId: identity?.externalId,\n location: `${state.url.origin}${state.url.pathname}/${group._id}`,\n }),\n ),\n totalResults: filtered.length,\n startIndex: listRequest.startIndex,\n itemsPerPage: paged.length,\n });\n };\n\n const handleGroupsPost: ScimHandler = async (state) => {\n const body = await readScimJson(state.request);\n const { groupId } = await auth.group.create(state.ctx, {\n name: String(body.displayName ?? \"Group\"),\n parentGroupId: state.enterprise.groupId,\n type: \"organization\",\n });\n await state.ctx.runMutation(\n config.component.public.enterpriseScimIdentityUpsert,\n {\n enterpriseId: state.enterprise._id,\n groupId: state.enterprise.groupId,\n resourceType: \"group\",\n externalId: body.externalId ?? groupId,\n mappedGroupId: groupId,\n active: true,\n raw: body,\n lastProvisionedAt: Date.now(),\n },\n );\n for (const member of Array.isArray(body.members) ? body.members : []) {\n try {\n await auth.member.create(state.ctx, {\n groupId,\n userId: String(member.value),\n roleIds: state.policy.provisioning.jit.defaultRoleIds,\n status: \"active\",\n });\n } catch {}\n }\n await state.recordScimEvent(\n \"enterprise.scim.group.created\",\n true,\n \"group\",\n groupId,\n );\n const group = await auth.group.get(state.ctx, groupId);\n const location = `${state.url.origin}${state.url.pathname}/${groupId}`;\n return scimJson(\n serializeScimGroup({\n id: groupId,\n group: group ?? {},\n externalId: body.externalId,\n location,\n members: (\n await auth.member.list(state.ctx, {\n where: { groupId, status: \"active\" },\n limit: 100,\n })\n ).items.map((member: any) => ({ value: member.userId })),\n }),\n 201,\n { Location: location },\n );\n };\n\n const handleGroupsPatch: ScimHandler = async (state) => {\n const missing = requireScimResourceId(\n state.parsedPath.resourceId,\n \"Group\",\n );\n if (missing) return missing;\n const groupId = state.parsedPath.resourceId!;\n const body = await readScimJson(state.request);\n for (const operation of Array.isArray(body.Operations)\n ? body.Operations\n : []) {\n if (operation.path === \"displayName\") {\n await auth.group.update(state.ctx, groupId, {\n name: operation.value,\n });\n }\n if (operation.path === \"members\" && operation.op === \"add\") {\n for (const member of Array.isArray(operation.value)\n ? operation.value\n : []) {\n try {\n await auth.member.create(state.ctx, {\n groupId,\n userId: String(member.value),\n roleIds: state.policy.provisioning.jit.defaultRoleIds,\n status: \"active\",\n });\n } catch {}\n }\n }\n if (operation.path === \"members\" && operation.op === \"replace\") {\n const currentMembers = (\n await auth.member.list(state.ctx, {\n where: { groupId, status: \"active\" },\n limit: 100,\n })\n ).items as Array<{ _id: string; userId: string }>;\n const currentUserIds = new Set<string>(\n currentMembers.map((member) => member.userId),\n );\n const nextUserIds = new Set<string>(\n (Array.isArray(operation.value) ? operation.value : []).map(\n (member: any) => String(member.value),\n ),\n );\n for (const member of currentMembers) {\n if (!nextUserIds.has(member.userId)) {\n await auth.member.delete(state.ctx, member._id);\n }\n }\n for (const userId of nextUserIds.values()) {\n if (!currentUserIds.has(userId)) {\n try {\n await auth.member.create(state.ctx, {\n groupId,\n userId,\n roleIds: state.policy.provisioning.jit.defaultRoleIds,\n status: \"active\",\n });\n } catch {}\n }\n }\n }\n if (\n typeof operation.path === \"string\" &&\n operation.op === \"remove\" &&\n operation.path.startsWith(\"members[\")\n ) {\n const match = operation.path.match(\n /^members\\[value eq \"([^\"]+)\"\\]$/,\n );\n const userId = match?.[1];\n if (userId) {\n const resolution = await auth.member.inspect(state.ctx, {\n groupId,\n userId,\n });\n if (resolution.membership) {\n await auth.member.delete(state.ctx, resolution.membership._id);\n }\n }\n }\n }\n await state.recordScimEvent(\n \"enterprise.scim.group.updated\",\n true,\n \"group\",\n groupId,\n );\n const group = await auth.group.get(state.ctx, groupId);\n const location = `${state.url.origin}${state.url.pathname}`;\n const members = (\n await auth.member.list(state.ctx, {\n where: { groupId, status: \"active\" },\n limit: 100,\n })\n ).items as Array<{ userId: string }>;\n return scimJson(\n serializeScimGroup({\n id: groupId,\n group: group ?? {},\n location,\n members: members.map((member) => ({\n value: member.userId,\n })),\n }),\n 200,\n { Location: location },\n );\n };\n\n const handleGroupsDelete: ScimHandler = async (state) => {\n const missing = requireScimResourceId(\n state.parsedPath.resourceId,\n \"Group\",\n );\n if (missing) return missing;\n const groupId = state.parsedPath.resourceId!;\n await auth.group.delete(state.ctx, groupId);\n const identity = await state.ctx.runQuery(\n config.component.public.enterpriseScimIdentityGetByMappedGroup,\n { mappedGroupId: groupId },\n );\n if (identity) {\n await state.ctx.runMutation(\n config.component.public.enterpriseScimIdentityDelete,\n { identityId: identity._id },\n );\n }\n await state.recordScimEvent(\n \"enterprise.scim.group.deleted\",\n true,\n \"group\",\n groupId,\n );\n return new Response(null, { status: 204 });\n };\n\n const scimHandlers: Record<\n string,\n Partial<Record<string, ScimHandler>>\n > = {\n ServiceProviderConfig: {\n GET: async () =>\n scimJson({\n schemas: [\n \"urn:ietf:params:scim:schemas:core:2.0:ServiceProviderConfig\",\n ],\n patch: { supported: true },\n bulk: {\n supported: false,\n maxOperations: 0,\n maxPayloadSize: 0,\n },\n filter: { supported: true, maxResults: 100 },\n changePassword: { supported: false },\n sort: { supported: false },\n etag: { supported: false },\n authenticationSchemes: [\n {\n type: \"oauthbearertoken\",\n name: \"Bearer Token\",\n description:\n \"Use the SCIM token generated by Convex Auth enterprise.\",\n },\n ],\n }),\n },\n Schemas: {\n GET: async (state) =>\n handleStaticScimCollection(\n SCIM_SCHEMAS,\n state.parsedPath.resourceId,\n {\n by: \"id\",\n notFound: \"Schema not found.\",\n },\n ),\n },\n ResourceTypes: {\n GET: async (state) =>\n handleStaticScimCollection(\n SCIM_RESOURCE_TYPES,\n state.parsedPath.resourceId,\n { by: \"name\", notFound: \"Resource type not found.\" },\n ),\n },\n Users: {\n GET: handleUsersGet,\n POST: handleUsersPost,\n PATCH: handleUsersUpsert,\n PUT: handleUsersUpsert,\n DELETE: handleUsersDelete,\n },\n Groups: {\n GET: handleGroupsGet,\n POST: handleGroupsPost,\n PATCH: handleGroupsPatch,\n DELETE: handleGroupsDelete,\n },\n };\n\n const handler =\n scimHandlers[state.parsedPath.resource]?.[state.request.method];\n return handler\n ? await handler(state)\n : scimError(404, \"notFound\", \"SCIM resource not found.\");\n } catch (error) {\n if (\n error instanceof Error &&\n error.message === \"Unsupported SCIM filter.\"\n ) {\n return scimError(400, \"invalidFilter\", error.message);\n }\n if (\n error instanceof ConvexError &&\n typeof error.data === \"object\" &&\n error.data !== null &&\n \"code\" in error.data &&\n \"message\" in error.data\n ) {\n const code = error.data.code as string;\n const status =\n code === \"MISSING_BEARER_TOKEN\" || code === \"INVALID_API_KEY\"\n ? 401\n : 400;\n return scimError(status, code, error.data.message);\n }\n throw error;\n }\n };\n\n addSSORoutes(http, {\n routeBase: ENTERPRISE_CONTROL_ROUTE_BASE,\n convertErrorsToResponse,\n handleSamlMetadata: async (ctx, _request, runtimeRoute) => {\n const { loaded } = await loadActiveEnterpriseSamlOrThrow(\n ctx,\n runtimeRoute.enterpriseId,\n );\n return new Response(\n createEnterpriseSamlMetadataXml({\n rootUrl: requireEnv(\"CONVEX_SITE_URL\"),\n source: loaded.source,\n config: loaded.config,\n }),\n {\n status: 200,\n headers: { \"Content-Type\": \"application/xml\" },\n },\n );\n },\n handleSamlSignIn: async (ctx, request, runtimeRoute) => {\n const url = new URL(request.url);\n const verifier = url.searchParams.get(\"code\");\n if (!verifier) {\n throw Cv.error({\n code: \"OAUTH_MISSING_VERIFIER\",\n message: \"Missing sign-in verifier.\",\n });\n }\n const { loaded, enterprise } = await loadActiveEnterpriseSamlOrThrow(\n ctx,\n runtimeRoute.enterpriseId,\n );\n const state = generateRandomString(24, INVITE_TOKEN_ALPHABET);\n const signInRequest = createEnterpriseSamlSignInRequest({\n rootUrl: requireEnv(\"CONVEX_SITE_URL\"),\n source: { kind: \"enterprise\", id: enterprise._id },\n config: loaded.config,\n state,\n signature: `saml ${enterprise._id} pending ${state}`,\n redirectTo: url.searchParams.get(\"redirectTo\") ?? undefined,\n });\n const signature = `saml ${enterprise._id} ${signInRequest.requestId} ${state}`;\n await callVerifierSignature(ctx, { verifier, signature });\n const redirectTo = url.searchParams.get(\"redirectTo\");\n const redirectCookies =\n redirectTo !== null\n ? [\n redirectToParamCookie(\n enterpriseSamlProviderId(enterprise._id),\n redirectTo,\n ),\n ]\n : [];\n const relayState = encodeEnterpriseSamlRelayState({\n source: { kind: \"enterprise\", id: enterprise._id },\n signature,\n requestId: signInRequest.requestId,\n state,\n redirectTo: url.searchParams.get(\"redirectTo\") ?? undefined,\n });\n if (signInRequest.binding === \"redirect\" && signInRequest.redirectUrl) {\n const redirectUrl = new URL(signInRequest.redirectUrl);\n redirectUrl.searchParams.set(\"RelayState\", relayState);\n const headers = new Headers({\n Location: redirectUrl.toString(),\n });\n for (const { name, value, options } of redirectCookies as any) {\n headers.append(\"Set-Cookie\", serializeCookie(name, value, options));\n }\n return new Response(null, { status: 302, headers });\n }\n const response = createSamlPostBindingResponse({\n endpoint: signInRequest.post!.endpoint,\n parameter: \"SAMLRequest\",\n value: signInRequest.post!.value,\n relayState,\n });\n for (const { name, value, options } of redirectCookies as any) {\n response.headers.append(\n \"Set-Cookie\",\n serializeCookie(name, value, options),\n );\n }\n return response;\n },\n handleOidcSignIn: async (ctx, request, runtimeRoute) => {\n const url = new URL(request.url);\n const verifier = url.searchParams.get(\"code\");\n if (!verifier) {\n throw Cv.error({\n code: \"OAUTH_MISSING_VERIFIER\",\n message: \"Missing sign-in verifier.\",\n });\n }\n const { enterprise, oidc } = await loadEnterpriseOidcOrThrow(\n ctx,\n runtimeRoute.enterpriseId,\n );\n const { providerId, provider, oauthConfig } =\n await createEnterpriseOidcRuntime({\n rootUrl: requireEnv(\"CONVEX_SITE_URL\"),\n enterpriseId: enterprise._id,\n oidc,\n });\n const { redirect, cookies, signature } =\n await createOAuthAuthorizationURL(providerId, provider, oauthConfig);\n await callVerifierSignature(ctx, { verifier, signature });\n const redirectTo = url.searchParams.get(\"redirectTo\");\n const headers_ = new Headers({ Location: redirect });\n for (const { name, value, options } of [\n ...cookies,\n ...(redirectTo !== null\n ? [redirectToParamCookie(providerId, redirectTo)]\n : []),\n ] as any) {\n headers_.append(\"Set-Cookie\", serializeCookie(name, value, options));\n }\n return new Response(null, {\n status: 302,\n headers: headers_,\n });\n },\n handleOidcCallback: async (ctx, request, runtimeRoute) => {\n const url = new URL(request.url);\n const { enterprise, oidc } = await loadEnterpriseOidcOrThrow(\n ctx,\n runtimeRoute.enterpriseId,\n );\n const { providerId, provider, oauthConfig } =\n await createEnterpriseOidcRuntime({\n rootUrl: requireEnv(\"CONVEX_SITE_URL\"),\n enterpriseId: enterprise._id,\n oidc,\n });\n const cookies = getCookies(request);\n const maybeRedirectTo = useRedirectToParam(providerId, cookies);\n const destinationUrl = await redirectAbsoluteUrl(config, {\n redirectTo: maybeRedirectTo?.redirectTo,\n });\n const params = url.searchParams;\n const result = (await Fx.run(\n handleOAuthCallback(\n providerId,\n provider,\n oauthConfig,\n Object.fromEntries(params.entries()),\n cookies,\n ),\n )) as any;\n const extraFields = oidc.extraFields as\n | Record<string, string>\n | undefined;\n let profile = result.profile as Record<string, unknown>;\n if (extraFields && typeof profile === \"object\" && profile) {\n const extend: Record<string, unknown> = {};\n for (const [claimName, fieldName] of Object.entries(extraFields)) {\n if (claimName in profile) {\n extend[fieldName] = profile[claimName];\n }\n }\n if (Object.keys(extend).length > 0) {\n profile = { ...profile, extend };\n }\n }\n\n const verificationCode = await callUserOAuth(ctx, {\n provider: providerId,\n providerAccountId: result.providerAccountId,\n profile,\n signature: result.signature,\n accountExtend: {\n identity: {\n protocol: \"oidc\",\n enterpriseId: enterprise._id,\n subject: result.providerAccountId,\n issuer: typeof oidc.issuer === \"string\" ? oidc.issuer : undefined,\n discoveryUrl:\n typeof oidc.discoveryUrl === \"string\"\n ? oidc.discoveryUrl\n : undefined,\n },\n },\n });\n const headers = new Headers({\n Location: setURLSearchParam(destinationUrl, \"code\", verificationCode),\n });\n for (const { name, value, options } of result.cookies) {\n headers.append(\n \"Set-Cookie\",\n serializeCookie(name, value, options as any),\n );\n }\n if (maybeRedirectTo) {\n headers.append(\n \"Set-Cookie\",\n serializeCookie(\n maybeRedirectTo.updatedCookie.name,\n maybeRedirectTo.updatedCookie.value,\n maybeRedirectTo.updatedCookie.options as any,\n ),\n );\n }\n return new Response(null, { status: 302, headers });\n },\n handleSamlAcs,\n handleSamlSlo,\n handleScimRequest,\n scimError,\n });\n}\n"],"mappings":"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"}
@@ -1,8 +1,86 @@
1
1
  import { CorsConfig, HttpKeyContext } from "./types.js";
2
- import * as convex_server0 from "convex/server";
2
+ import { AuthContext, OptionalAuthContext, UserDoc } from "./auth.js";
3
+ import * as convex_server65 from "convex/server";
3
4
  import { GenericActionCtx, GenericDataModel, HttpRouter } from "convex/server";
4
5
 
5
6
  //#region src/server/http.d.ts
7
+ /**
8
+ * Auth context returned by `auth.http.context(ctx, request)`.
9
+ *
10
+ * This resolves raw HTTP authentication in two steps:
11
+ * 1. session auth from `ctx.auth.getUserIdentity()`
12
+ * 2. API key auth from `Authorization: Bearer sk_*`
13
+ *
14
+ * The `source` field tells you which authentication path succeeded.
15
+ * When `source === "key"`, the verified API key metadata is available on
16
+ * `key`.
17
+ *
18
+ * @example
19
+ * ```ts
20
+ * const authContext = await auth.http.context(ctx, request);
21
+ * if (authContext.source === "key") {
22
+ * console.log(authContext.key.keyId);
23
+ * }
24
+ * ```
25
+ */
26
+ type HttpAuthContext = (AuthContext & {
27
+ /** The request authenticated through a browser or session token. */source: "session"; /** No API key was used for this request. */
28
+ key: null;
29
+ }) | (AuthContext & {
30
+ /** The request authenticated through an API key. */source: "key"; /** Verified API key metadata for the request. */
31
+ key: HttpKeyContext["key"];
32
+ });
33
+ /**
34
+ * Nullable HTTP auth context returned by
35
+ * `auth.http.context(ctx, request, { optional: true })`.
36
+ *
37
+ * This preserves a stable auth-shaped object for raw `httpAction` handlers
38
+ * that allow anonymous callers.
39
+ */
40
+ type OptionalHttpAuthContext = (OptionalAuthContext & {
41
+ /** No authentication source was resolved. */source: null; /** No API key metadata is available. */
42
+ key: null;
43
+ }) | HttpAuthContext;
44
+ /**
45
+ * Configuration for {@link createAuth().http.context}.
46
+ *
47
+ * This mirrors {@link AuthContextConfig} for raw HTTP handlers and adds support
48
+ * for enriching mixed session/API-key auth results.
49
+ *
50
+ * @typeParam TResolve - Extra fields returned from `resolve()` and merged into
51
+ * the resolved HTTP auth context.
52
+ *
53
+ * @example
54
+ * ```ts
55
+ * const authContext = await auth.http.context(ctx, request, {
56
+ * resolve: async (_ctx, user, authState) => ({
57
+ * email: user.email,
58
+ * isMachineRequest: authState.source === "key",
59
+ * }),
60
+ * });
61
+ * ```
62
+ */
63
+ type HttpAuthContextConfig<TResolve extends Record<string, unknown> = Record<string, never>> = {
64
+ /**
65
+ * Allow unauthenticated callers and return a null-shaped auth object instead
66
+ * of throwing `NOT_SIGNED_IN`.
67
+ */
68
+ optional?: boolean;
69
+ /**
70
+ * Attach additional derived fields to the resolved HTTP auth context.
71
+ *
72
+ * This callback runs only when authentication succeeds.
73
+ */
74
+ resolve?: (ctx: GenericActionCtx<any>, user: UserDoc, auth: HttpAuthContext) => Promise<TResolve> | TResolve;
75
+ /**
76
+ * Override or wrap HTTP auth resolution.
77
+ *
78
+ * Return `undefined` to use the built-in session-or-key resolver, `null` for
79
+ * an explicit unauthenticated state, or a fully resolved
80
+ * {@link HttpAuthContext}.
81
+ */
82
+ authResolve?: (ctx: GenericActionCtx<any>, fallback: () => Promise<HttpAuthContext | null>) => Promise<HttpAuthContext | null | undefined> | HttpAuthContext | null | undefined;
83
+ };
6
84
  declare function createHttpAction(auth: {
7
85
  key: {
8
86
  verify: (ctx: GenericActionCtx<any>, rawKey: string) => Promise<any>;
@@ -13,7 +91,7 @@ declare function createHttpAction(auth: {
13
91
  action: string;
14
92
  };
15
93
  cors?: CorsConfig;
16
- }) => convex_server0.PublicHttpAction;
94
+ }) => convex_server65.PublicHttpAction;
17
95
  declare function createHttpRoute(wrapAction: ReturnType<typeof createHttpAction>): (http: {
18
96
  route: (config: any) => void;
19
97
  }, routeConfig: {
@@ -55,5 +133,5 @@ declare function addSSORoutes(http: HttpRouter, deps: {
55
133
  scimError: (status: number, scimType: string, detail: string) => Response;
56
134
  }): void;
57
135
  //#endregion
58
- export { SSORuntimeRoute, addAuthRoutes, addOpenIdRoutes, addSSORoutes, convertErrorsToResponse, createHttpAction, createHttpRoute, getCookies };
136
+ export { HttpAuthContext, HttpAuthContextConfig, OptionalHttpAuthContext, SSORuntimeRoute, addAuthRoutes, addOpenIdRoutes, addSSORoutes, convertErrorsToResponse, createHttpAction, createHttpRoute, getCookies };
59
137
  //# sourceMappingURL=http.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"http.d.ts","names":[],"sources":["../../src/server/http.ts"],"mappings":";;;;;iBAgBgB,gBAAA,CAAiB,IAAA;EAC/B,GAAA;IAAO,MAAA,GAAS,GAAA,EAAK,gBAAA,OAAuB,MAAA,aAAmB,OAAA;EAAA;AAAA,KAG7D,OAAA,GACE,GAAA,EAAK,gBAAA,CAAiB,gBAAA,IAAoB,cAAA,EAC1C,OAAA,EAAS,OAAA,KACN,OAAA,CAAQ,QAAA,GAAW,MAAA,oBACxB,OAAA;EACE,KAAA;IAAU,QAAA;IAAkB,MAAA;EAAA;EAC5B,IAAA,GAAO,UAAA;AAAA,MAAU,cAAA,CAClB,gBAAA;AAAA,iBA2IW,eAAA,CACd,UAAA,EAAY,UAAA,QAAkB,gBAAA,KAG5B,IAAA;EAAQ,KAAA,GAAQ,MAAA;AAAA,GAChB,WAAA;EACE,IAAA;EACA,MAAA;EACA,OAAA,GACE,GAAA,EAAK,gBAAA,CAAiB,gBAAA,IAAoB,cAAA,EAC1C,OAAA,EAAS,OAAA,KACN,OAAA,CAAQ,QAAA,GAAW,MAAA;EACxB,KAAA;IAAU,QAAA;IAAkB,MAAA;EAAA;EAC5B,IAAA,GAAO,UAAA;AAAA;AAAA,iBA+BG,uBAAA,CACd,eAAA,UACA,MAAA,GAAS,GAAA,EAAK,gBAAA,OAAuB,OAAA,EAAS,OAAA,KAAY,OAAA,CAAQ,QAAA,KAEpD,GAAA,EAAK,gBAAA,OAAuB,OAAA,EAAS,OAAA,KAAO,OAAA,CAAA,QAAA;AAAA,iBA2C5C,UAAA,CACd,OAAA,EAAS,OAAA,GACR,MAAA;AAAA,KAIS,eAAA;EACV,QAAA;EACA,YAAA;EACA,QAAA;EACA,IAAA;AAAA;AAAA,iBA2Bc,eAAA,CACd,IAAA,EAAM,UAAA,EACN,IAAA;EACE,SAAA;EACA,OAAA;AAAA;AAAA,iBA0CY,aAAA,CACd,IAAA,EAAM,UAAA,EACN,IAAA;EACE,YAAA,GACE,GAAA,EAAK,gBAAA,OACL,OAAA,EAAS,OAAA,KACN,OAAA,CAAQ,QAAA;EACb,cAAA,GACE,GAAA,EAAK,gBAAA,OACL,OAAA,EAAS,OAAA,KACN,OAAA,CAAQ,QAAA;AAAA;AAAA,iBAwBD,YAAA,CACd,IAAA,EAAM,UAAA,EACN,IAAA;EACE,SAAA;EACA,uBAAA,SAAgC,uBAAA;EAChC,kBAAA,GACE,GAAA,EAAK,gBAAA,OACL,OAAA,EAAS,OAAA,EACT,KAAA,EAAO,eAAA,KACJ,OAAA,CAAQ,QAAA;EACb,gBAAA,GACE,GAAA,EAAK,gBAAA,OACL,OAAA,EAAS,OAAA,EACT,KAAA,EAAO,eAAA,KACJ,OAAA,CAAQ,QAAA;EACb,gBAAA,GACE,GAAA,EAAK,gBAAA,OACL,OAAA,EAAS,OAAA,EACT,KAAA,EAAO,eAAA,KACJ,OAAA,CAAQ,QAAA;EACb,kBAAA,GACE,GAAA,EAAK,gBAAA,OACL,OAAA,EAAS,OAAA,EACT,KAAA,EAAO,eAAA,KACJ,OAAA,CAAQ,QAAA;EACb,aAAA,GACE,GAAA,EAAK,gBAAA,OACL,OAAA,EAAS,OAAA,EACT,KAAA,EAAO,eAAA,KACJ,OAAA,CAAQ,QAAA;EACb,aAAA,GACE,GAAA,EAAK,gBAAA,OACL,OAAA,EAAS,OAAA,EACT,KAAA,EAAO,eAAA,KACJ,OAAA,CAAQ,QAAA;EACb,iBAAA,GACE,GAAA,EAAK,gBAAA,OACL,OAAA,EAAS,OAAA,KACN,OAAA,CAAQ,QAAA;EACb,SAAA,GAAY,MAAA,UAAgB,QAAA,UAAkB,MAAA,aAAmB,QAAA;AAAA"}
1
+ {"version":3,"file":"http.d.ts","names":[],"sources":["../../src/server/http.ts"],"mappings":"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"}
@@ -1,12 +1,69 @@
1
- import { isAuthError } from "./errors.js";
2
- import { AuthError } from "./authError.js";
1
+ import { createUnauthenticatedAuthContext, getAuthContextForUser, getSessionUserId } from "./context.js";
3
2
  import { logError } from "./utils.js";
4
3
  import { Fx } from "@robelest/fx";
4
+ import { Cv } from "@robelest/fx/convex";
5
5
  import { httpActionGeneric } from "convex/server";
6
6
  import { ConvexError } from "convex/values";
7
7
  import { parse } from "cookie";
8
8
 
9
9
  //#region src/server/http.ts
10
+ function createNotSignedInError() {
11
+ return Cv.error({
12
+ code: "NOT_SIGNED_IN",
13
+ message: "Authentication required."
14
+ });
15
+ }
16
+ async function getHttpKeyContext(auth, ctx, request) {
17
+ const authHeader = request.headers.get("Authorization");
18
+ if (!authHeader?.startsWith("Bearer sk_")) return null;
19
+ try {
20
+ const verified = await auth.key.verify(ctx, authHeader.slice(7));
21
+ return {
22
+ ...await getAuthContextForUser(auth, ctx, verified.userId),
23
+ source: "key",
24
+ key: {
25
+ userId: verified.userId,
26
+ keyId: verified.keyId,
27
+ scopes: verified.scopes
28
+ }
29
+ };
30
+ } catch {
31
+ return null;
32
+ }
33
+ }
34
+ async function resolveHttpAuthContext(auth, ctx, request) {
35
+ const sessionUserId = await getSessionUserId(ctx);
36
+ if (sessionUserId !== null) return {
37
+ ...await getAuthContextForUser(auth, ctx, sessionUserId),
38
+ source: "session",
39
+ key: null
40
+ };
41
+ return await getHttpKeyContext(auth, ctx, request);
42
+ }
43
+ /**
44
+ * @internal
45
+ * Create the implementation behind `auth.http.context(...)`.
46
+ */
47
+ function createHttpContext(auth) {
48
+ return (async (ctx, request, config) => {
49
+ const fallback = () => resolveHttpAuthContext(auth, ctx, request);
50
+ const authOverride = config?.authResolve ? await config.authResolve(ctx, fallback) : void 0;
51
+ const resolved = authOverride === void 0 ? await fallback() : authOverride;
52
+ if (resolved === null) {
53
+ if (config?.optional !== true) throw createNotSignedInError();
54
+ return {
55
+ ...createUnauthenticatedAuthContext(),
56
+ source: null,
57
+ key: null
58
+ };
59
+ }
60
+ const extra = config?.resolve ? await config.resolve(ctx, resolved.user, resolved) : {};
61
+ return {
62
+ ...resolved,
63
+ ...extra
64
+ };
65
+ });
66
+ }
10
67
  function createHttpAction(auth) {
11
68
  return (handler, options) => {
12
69
  const corsConfig = options?.cors ?? {};
@@ -30,21 +87,15 @@ function createHttpAction(auth) {
30
87
  }
31
88
  });
32
89
  const rawKey = authHeader.slice(7);
33
- const keyResult = await Fx.run(Fx.from({
34
- ok: () => auth.key.verify(genericCtx, rawKey),
35
- err: (error) => error
36
- }).pipe(Fx.fold({
37
- ok: (result$1) => ({
38
- ok: true,
39
- value: result$1
40
- }),
41
- err: (error) => ({
42
- ok: false,
43
- error
44
- })
90
+ const keyResult = await Fx.run(Fx.attempt(() => auth.key.verify(genericCtx, rawKey), (result$1) => ({
91
+ ok: true,
92
+ value: result$1
93
+ }), (error) => ({
94
+ ok: false,
95
+ error
45
96
  })));
46
97
  if (!keyResult.ok) {
47
- if (isAuthError(keyResult.error)) {
98
+ if (keyResult.error instanceof ConvexError && typeof keyResult.error.data === "object" && keyResult.error.data !== null && "code" in keyResult.error.data && "message" in keyResult.error.data) {
48
99
  const { code, message } = keyResult.error.data;
49
100
  return new Response(JSON.stringify({
50
101
  error: message,
@@ -142,7 +193,7 @@ function convertErrorsToResponse(errorStatusCode, action) {
142
193
  ok: () => action(ctx, request),
143
194
  err: (error) => error
144
195
  }).pipe(Fx.recover((error) => {
145
- if (isAuthError(error)) return Fx.succeed(new Response(JSON.stringify({
196
+ if (error instanceof ConvexError && typeof error.data === "object" && error.data !== null && "code" in error.data && "message" in error.data) return Fx.succeed(new Response(JSON.stringify({
146
197
  code: error.data.code,
147
198
  message: error.data.message
148
199
  }), {
@@ -235,7 +286,10 @@ function addSSORoutes(http, deps) {
235
286
  method: "GET",
236
287
  handler: httpActionGeneric(deps.convertErrorsToResponse(400, async (ctx, request) => {
237
288
  const route = parseEnterpriseRuntimeRoute(new URL(request.url).pathname, deps.routeBase);
238
- if (!route) throw new AuthError("INVALID_PARAMETERS", "Invalid enterprise runtime path.").toConvexError();
289
+ if (!route) throw Cv.error({
290
+ code: "INVALID_PARAMETERS",
291
+ message: "Invalid enterprise runtime path."
292
+ });
239
293
  if (route.protocol === "saml" && route.rest.length === 1) {
240
294
  if (route.rest[0] === "metadata") return await deps.handleSamlMetadata(ctx, request, route);
241
295
  if (route.rest[0] === "signin") return await deps.handleSamlSignIn(ctx, request, route);
@@ -247,7 +301,10 @@ function addSSORoutes(http, deps) {
247
301
  if (route.rest[0] === "callback") return await deps.handleOidcCallback(ctx, request, route);
248
302
  }
249
303
  if (route.protocol === "scim" && route.rest[0] === "v2") return await deps.handleScimRequest(ctx, request);
250
- throw new AuthError("INVALID_PARAMETERS", "Invalid enterprise runtime path.").toConvexError();
304
+ throw Cv.error({
305
+ code: "INVALID_PARAMETERS",
306
+ message: "Invalid enterprise runtime path."
307
+ });
251
308
  }))
252
309
  });
253
310
  http.route({
@@ -260,7 +317,10 @@ function addSSORoutes(http, deps) {
260
317
  if (route.rest[0] === "slo") return await deps.handleSamlSlo(ctx, request, route);
261
318
  }
262
319
  if (route?.protocol === "scim" && route.rest[0] === "v2") return await deps.handleScimRequest(ctx, request);
263
- throw new AuthError("INVALID_PARAMETERS", "Invalid enterprise runtime path.").toConvexError();
320
+ throw Cv.error({
321
+ code: "INVALID_PARAMETERS",
322
+ message: "Invalid enterprise runtime path."
323
+ });
264
324
  }))
265
325
  });
266
326
  http.route({
@@ -269,7 +329,10 @@ function addSSORoutes(http, deps) {
269
329
  handler: httpActionGeneric(deps.convertErrorsToResponse(400, async (ctx, request) => {
270
330
  const route = parseEnterpriseRuntimeRoute(new URL(request.url).pathname, deps.routeBase);
271
331
  if (route?.protocol === "scim" && route.rest[0] === "v2") return await deps.handleScimRequest(ctx, request);
272
- throw new AuthError("INVALID_PARAMETERS", "Invalid enterprise runtime path.").toConvexError();
332
+ throw Cv.error({
333
+ code: "INVALID_PARAMETERS",
334
+ message: "Invalid enterprise runtime path."
335
+ });
273
336
  }))
274
337
  });
275
338
  for (const method of ["PATCH", "DELETE"]) http.route({
@@ -284,5 +347,5 @@ function addSSORoutes(http, deps) {
284
347
  }
285
348
 
286
349
  //#endregion
287
- export { addAuthRoutes, addOpenIdRoutes, addSSORoutes, convertErrorsToResponse, createHttpAction, createHttpRoute, getCookies };
350
+ export { addAuthRoutes, addOpenIdRoutes, addSSORoutes, convertErrorsToResponse, createHttpAction, createHttpContext, createHttpRoute, getCookies };
288
351
  //# sourceMappingURL=http.js.map