@robelest/convex-auth 0.0.4-preview.27 → 0.0.4-preview.28

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 (88) hide show
  1. package/README.md +3 -5
  2. package/dist/bin.js +6488 -1571
  3. package/dist/browser/index.js +10 -7
  4. package/dist/browser/locks.js +3 -5
  5. package/dist/browser/navigation.js +7 -10
  6. package/dist/browser/runtime.js +35 -33
  7. package/dist/client/core/types.js +17 -0
  8. package/dist/client/factors/device.js +26 -19
  9. package/dist/client/index.js +151 -163
  10. package/dist/client/runtime/proxy.js +6 -6
  11. package/dist/client/services/adapters.js +3 -7
  12. package/dist/client/services/http.js +2 -5
  13. package/dist/client/services/resolve.js +5 -11
  14. package/dist/client/services/runtime.js +2 -5
  15. package/dist/component/_generated/component.d.ts +46 -0
  16. package/dist/component/index.d.ts +3 -3
  17. package/dist/component/model.d.ts +25 -25
  18. package/dist/component/public/identity/sessions.js +38 -1
  19. package/dist/component/public/identity/tokens.js +81 -3
  20. package/dist/component/public/identity/verifiers.js +9 -3
  21. package/dist/component/public.js +3 -3
  22. package/dist/component/schema.d.ts +320 -320
  23. package/dist/core/index.d.ts +380 -0
  24. package/dist/core/index.js +83 -0
  25. package/dist/otel.d.ts +13 -17
  26. package/dist/otel.js +39 -49
  27. package/dist/providers/email.d.ts +2 -2
  28. package/dist/providers/password.js +8 -16
  29. package/dist/providers/phone.js +2 -9
  30. package/dist/server/auth-context.d.ts +204 -0
  31. package/dist/server/auth-context.js +76 -0
  32. package/dist/server/auth.d.ts +25 -187
  33. package/dist/server/auth.js +5 -96
  34. package/dist/server/componentContext.d.ts +12 -0
  35. package/dist/server/componentContext.js +1 -0
  36. package/dist/server/config.js +1 -12
  37. package/dist/server/constants.js +6 -0
  38. package/dist/server/contract.d.ts +1 -1
  39. package/dist/server/core.js +5 -14
  40. package/dist/server/crypto.js +26 -18
  41. package/dist/server/db.js +6 -1
  42. package/dist/server/device.js +88 -78
  43. package/dist/server/http.d.ts +4 -3
  44. package/dist/server/http.js +74 -86
  45. package/dist/server/index.d.ts +2 -1
  46. package/dist/server/limits.js +22 -15
  47. package/dist/server/mounts.d.ts +103 -103
  48. package/dist/server/mutations/account.js +6 -4
  49. package/dist/server/mutations/invalidate.js +3 -6
  50. package/dist/server/mutations/oauth.js +86 -88
  51. package/dist/server/mutations/refresh.js +45 -87
  52. package/dist/server/mutations/register.js +19 -19
  53. package/dist/server/mutations/retrieve.js +17 -15
  54. package/dist/server/mutations/signature.js +9 -13
  55. package/dist/server/mutations/signin.js +7 -3
  56. package/dist/server/mutations/signout.js +10 -15
  57. package/dist/server/mutations/store.js +22 -12
  58. package/dist/server/mutations/verifier.js +11 -6
  59. package/dist/server/mutations/verify.js +55 -46
  60. package/dist/server/oauth/runtime.js +27 -25
  61. package/dist/server/passkey.js +299 -250
  62. package/dist/server/prefetch.js +283 -281
  63. package/dist/server/refresh.js +7 -60
  64. package/dist/server/runtime.d.ts +82 -206
  65. package/dist/server/runtime.js +63 -56
  66. package/dist/server/services/config.js +5 -3
  67. package/dist/server/services/logger.js +2 -4
  68. package/dist/server/services/providers.js +2 -4
  69. package/dist/server/services/refresh.js +2 -4
  70. package/dist/server/services/resolve.js +15 -14
  71. package/dist/server/services/signin.js +2 -4
  72. package/dist/server/sessions.js +32 -33
  73. package/dist/server/signin.js +177 -142
  74. package/dist/server/sso/domain.d.ts +20 -68
  75. package/dist/server/sso/domain.js +444 -413
  76. package/dist/server/sso/http.js +53 -59
  77. package/dist/server/sso/oidc.js +94 -80
  78. package/dist/server/tokens.js +13 -3
  79. package/dist/server/totp.js +153 -116
  80. package/dist/server/types.d.ts +2 -2
  81. package/dist/server/users.js +18 -23
  82. package/dist/server/utils/cache.js +51 -0
  83. package/dist/server/utils/dispatch.js +36 -0
  84. package/dist/server/utils/retry.js +24 -0
  85. package/dist/server/utils/span.js +32 -0
  86. package/dist/shared/errors.js +9 -3
  87. package/dist/shared/log.js +20 -22
  88. package/package.json +41 -33
@@ -1,21 +1,20 @@
1
- import { envOptionalString, readConfigSync, requireEnv } from "./env.js";
2
1
  import { generateRandomString } from "./random.js";
3
- import { authFlowError } from "../shared/errors.js";
4
- import { toConvexError } from "./errors.js";
2
+ import { envOptionalString, readConfigSync, requireEnv } from "./env.js";
5
3
  import { log } from "./log.js";
6
4
  import { callCreateVerificationCode } from "./mutations/code.js";
5
+ import { withSpan } from "./utils/span.js";
7
6
  import { callRefreshSession } from "./mutations/refresh.js";
8
- import { callVerifierSignature } from "./mutations/signature.js";
9
7
  import { callSignIn } from "./mutations/signin.js";
10
8
  import { callVerifier } from "./mutations/verifier.js";
11
9
  import { callVerifyCodeAndSignIn } from "./mutations/verify.js";
10
+ import { redirectAbsoluteUrl, setURLSearchParam } from "./redirects.js";
11
+ import { authFlowError } from "../shared/errors.js";
12
+ import { toConvexError } from "./errors.js";
12
13
  import { queryTotpVerifiedByUserId } from "./types.js";
13
14
  import { handleDevice } from "./device.js";
14
15
  import { handlePasskeyFx } from "./passkey.js";
15
- import { redirectAbsoluteUrl, setURLSearchParam } from "./redirects.js";
16
16
  import { handleTotp } from "./totp.js";
17
17
  import { ConvexError } from "convex/values";
18
- import { Effect, Match } from "effect";
19
18
 
20
19
  //#region src/server/signin.ts
21
20
  const DEFAULT_EMAIL_VERIFICATION_CODE_DURATION_S = 3600 * 24;
@@ -46,15 +45,16 @@ const asCredentialsError = (error) => {
46
45
  return toConvexError(authFlowError("INTERNAL_ERROR", "Failed to authorize credentials."));
47
46
  };
48
47
  async function signInImpl(ctx, provider, args, options) {
49
- return Effect.runPromise(signInFx(ctx, provider, args, options));
48
+ return signInFx(ctx, provider, args, options);
50
49
  }
51
- function signInFx(ctx, provider, args, options) {
52
- return Effect.gen(function* () {
53
- if (provider === null && args.refreshToken) {
54
- const tokens = yield* Effect.tryPromise({
55
- try: () => callRefreshSession(ctx, { refreshToken: args.refreshToken }),
56
- catch: (error) => asConvexError(error, "INTERNAL_ERROR", "Failed to refresh session.")
57
- });
50
+ async function signInFx(ctx, provider, args, options) {
51
+ return withSpan("convex-auth.signin", {
52
+ hasProvider: provider !== null,
53
+ hasCode: args.params?.code !== void 0,
54
+ hasRefreshToken: args.refreshToken !== void 0
55
+ }, async () => {
56
+ if (provider === null && args.refreshToken) try {
57
+ const tokens = await callRefreshSession(ctx, { refreshToken: args.refreshToken });
58
58
  if (tokens === null) return {
59
59
  kind: "signedIn",
60
60
  signedIn: null
@@ -63,171 +63,201 @@ function signInFx(ctx, provider, args, options) {
63
63
  kind: "refreshTokens",
64
64
  signedIn: { tokens }
65
65
  };
66
+ } catch (error) {
67
+ throw asConvexError(error, "INTERNAL_ERROR", "Failed to refresh session.");
66
68
  }
67
- if (provider === null && args.params?.code !== void 0) return {
68
- kind: "signedIn",
69
- signedIn: yield* Effect.tryPromise({
70
- try: () => callVerifyCodeAndSignIn(ctx, {
69
+ if (provider === null && args.params?.code !== void 0) try {
70
+ return {
71
+ kind: "signedIn",
72
+ signedIn: await callVerifyCodeAndSignIn(ctx, {
71
73
  params: args.params,
72
74
  verifier: args.verifier,
73
75
  generateTokens: true,
74
76
  allowExtraProviders: options.allowExtraProviders
75
- }),
76
- catch: (error) => asConvexError(error, "INTERNAL_ERROR", "Failed to verify sign-in code.")
77
- })
78
- };
77
+ })
78
+ };
79
+ } catch (error) {
80
+ throw asConvexError(error, "INTERNAL_ERROR", "Failed to verify sign-in code.");
81
+ }
79
82
  const resolvedProvider = provider;
80
- if (resolvedProvider === null) return yield* Effect.fail(toConvexError(authFlowError("SIGN_IN_MISSING_PARAMS", "Cannot sign in: missing provider, code, or refresh token.")));
81
- return yield* Match.value(resolvedProvider).pipe(Match.when({ type: "email" }, (provider$1) => handleEmailAndPhoneProviderFx(ctx, provider$1, args, options)), Match.when({ type: "phone" }, (provider$1) => handleEmailAndPhoneProviderFx(ctx, provider$1, args, options)), Match.when({ type: "credentials" }, (provider$1) => handleCredentialsFx(ctx, provider$1, args, options)), Match.when({ type: "oauth" }, (provider$1) => handleOAuthProviderFx(ctx, provider$1, args, options)), Match.when({ type: "passkey" }, (provider$1) => handlePasskeyFx(ctx, provider$1, args)), Match.when({ type: "totp" }, (provider$1) => handleTotp(ctx, provider$1, args)), Match.when({ type: "device" }, (provider$1) => handleDevice(ctx, provider$1, args)), Match.when({ type: "sso" }, () => handleSsoProviderFx(ctx, args, options)), Match.exhaustive);
82
- }).pipe(Effect.withSpan("convex-auth.signin", { attributes: {
83
- hasProvider: provider !== null,
84
- hasCode: args.params?.code !== void 0,
85
- hasRefreshToken: args.refreshToken !== void 0
86
- } }));
83
+ if (resolvedProvider === null) throw toConvexError(authFlowError("SIGN_IN_MISSING_PARAMS", "Cannot sign in: missing provider, code, or refresh token."));
84
+ const handler = {
85
+ email: () => handleEmailAndPhoneProviderFx(ctx, resolvedProvider, args, options),
86
+ phone: () => handleEmailAndPhoneProviderFx(ctx, resolvedProvider, args, options),
87
+ credentials: () => handleCredentialsFx(ctx, resolvedProvider, args, options),
88
+ oauth: () => handleOAuthProviderFx(ctx, resolvedProvider, args, options),
89
+ passkey: () => handlePasskeyFx(ctx, resolvedProvider, args),
90
+ totp: () => handleTotp(ctx, resolvedProvider, args),
91
+ device: () => handleDevice(ctx, resolvedProvider, args),
92
+ sso: () => handleSsoProviderFx(ctx, args, options)
93
+ }[resolvedProvider.type];
94
+ if (!handler) throw toConvexError(authFlowError("SIGN_IN_MISSING_PARAMS", `Unknown provider type: ${resolvedProvider.type}`));
95
+ return handler();
96
+ });
87
97
  }
88
- function handleEmailAndPhoneProviderFx(ctx, provider, args, options) {
89
- return Effect.gen(function* () {
98
+ async function handleEmailAndPhoneProviderFx(ctx, provider, args, options) {
99
+ return withSpan(`convex-auth.signin.${provider.type}`, {}, async () => {
90
100
  const normalizedParams = normalizeVerificationParams(args.params);
91
101
  if (args.params?.code !== void 0) {
92
- const result = yield* Effect.tryPromise({
93
- try: () => callVerifyCodeAndSignIn(ctx, {
102
+ let result;
103
+ try {
104
+ result = await callVerifyCodeAndSignIn(ctx, {
94
105
  params: args.params,
95
106
  provider: provider.id,
96
107
  generateTokens: options.generateTokens,
97
108
  allowExtraProviders: options.allowExtraProviders
98
- }),
99
- catch: (error) => asConvexError(error, "INTERNAL_ERROR", "Failed to verify email or phone code.")
100
- });
101
- if (result === null) return yield* Effect.fail(toConvexError(authFlowError("INVALID_VERIFICATION_CODE", "Invalid or expired verification code.")));
109
+ });
110
+ } catch (error) {
111
+ throw asConvexError(error, "INTERNAL_ERROR", "Failed to verify email or phone code.");
112
+ }
113
+ if (result === null) throw toConvexError(authFlowError("INVALID_VERIFICATION_CODE", "Invalid or expired verification code."));
102
114
  return {
103
115
  kind: "signedIn",
104
116
  signedIn: result
105
117
  };
106
118
  }
107
- const code = provider.generateVerificationToken ? yield* Effect.tryPromise({
108
- try: async () => provider.generateVerificationToken(),
109
- catch: () => toConvexError(authFlowError("INTERNAL_ERROR", "Failed to generate verification token"))
110
- }) : generateRandomString(32, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
119
+ const alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
120
+ let code;
121
+ if (provider.generateVerificationToken) try {
122
+ code = await provider.generateVerificationToken();
123
+ } catch {
124
+ throw toConvexError(authFlowError("INTERNAL_ERROR", "Failed to generate verification token"));
125
+ }
126
+ else code = generateRandomString(32, alphabet);
111
127
  const expirationTime = Date.now() + (provider.maxAge ?? DEFAULT_EMAIL_VERIFICATION_CODE_DURATION_S) * 1e3;
128
+ let identifier;
129
+ try {
130
+ identifier = await callCreateVerificationCode(ctx, {
131
+ provider: provider.id,
132
+ accountId: args.accountId,
133
+ email: normalizedParams.email,
134
+ phone: normalizedParams.phone,
135
+ code,
136
+ expirationTime,
137
+ allowExtraProviders: options.allowExtraProviders
138
+ });
139
+ } catch (error) {
140
+ throw asConvexError(error, "INTERNAL_ERROR", "Failed to create verification code.");
141
+ }
142
+ let destination;
143
+ try {
144
+ destination = await redirectAbsoluteUrl(ctx.auth.config, args.params ?? {});
145
+ } catch (error) {
146
+ throw asConvexError(error, "INVALID_REDIRECT", "Failed to resolve redirect URL.");
147
+ }
112
148
  const verificationArgs = {
113
- identifier: yield* Effect.tryPromise({
114
- try: () => callCreateVerificationCode(ctx, {
115
- provider: provider.id,
116
- accountId: args.accountId,
117
- email: normalizedParams.email,
118
- phone: normalizedParams.phone,
119
- code,
120
- expirationTime,
121
- allowExtraProviders: options.allowExtraProviders
122
- }),
123
- catch: (error) => asConvexError(error, "INTERNAL_ERROR", "Failed to create verification code.")
124
- }),
125
- url: setURLSearchParam(yield* Effect.tryPromise({
126
- try: () => redirectAbsoluteUrl(ctx.auth.config, args.params ?? {}),
127
- catch: (error) => asConvexError(error, "INVALID_REDIRECT", "Failed to resolve redirect URL.")
128
- }), "code", code),
149
+ identifier,
150
+ url: setURLSearchParam(destination, "code", code),
129
151
  token: code,
130
152
  expires: new Date(expirationTime)
131
153
  };
132
- yield* Match.value(provider).pipe(Match.when({ type: "email" }, (provider$1) => Effect.tryPromise({
133
- try: async () => {
134
- await provider$1.sendVerificationRequest({
135
- ...verificationArgs,
136
- provider: provider$1,
137
- request: new Request("http://localhost")
138
- }, ctx);
139
- },
140
- catch: () => toConvexError(authFlowError("INTERNAL_ERROR", "Failed to send email code"))
141
- })), Match.when({ type: "phone" }, (provider$1) => Effect.tryPromise({
142
- try: async () => {
143
- await provider$1.sendVerificationRequest({
144
- ...verificationArgs,
145
- provider: provider$1
146
- }, ctx);
147
- },
148
- catch: () => toConvexError(authFlowError("INTERNAL_ERROR", "Failed to send phone code"))
149
- })), Match.exhaustive);
154
+ if (provider.type === "email") try {
155
+ await provider.sendVerificationRequest({
156
+ ...verificationArgs,
157
+ provider,
158
+ request: new Request("http://localhost")
159
+ }, ctx);
160
+ } catch {
161
+ throw toConvexError(authFlowError("INTERNAL_ERROR", "Failed to send email code"));
162
+ }
163
+ else try {
164
+ await provider.sendVerificationRequest({
165
+ ...verificationArgs,
166
+ provider
167
+ }, ctx);
168
+ } catch {
169
+ throw toConvexError(authFlowError("INTERNAL_ERROR", "Failed to send phone code"));
170
+ }
150
171
  return {
151
172
  kind: "started",
152
173
  started: true
153
174
  };
154
- }).pipe(Effect.withSpan(`convex-auth.signin.${provider.type}`));
175
+ });
155
176
  }
156
- function handleCredentialsFx(ctx, provider, args, options) {
157
- return Effect.gen(function* () {
158
- const result = yield* Effect.tryPromise({
159
- try: () => provider.authorize(args.params ?? {}, ctx),
160
- catch: (error) => asCredentialsError(error)
161
- });
177
+ async function handleCredentialsFx(ctx, provider, args, options) {
178
+ return withSpan("convex-auth.signin.credentials", {}, async () => {
179
+ let result;
180
+ try {
181
+ result = await provider.authorize(args.params ?? {}, ctx);
182
+ } catch (error) {
183
+ throw asCredentialsError(error);
184
+ }
162
185
  if (result === null) return {
163
186
  kind: "signedIn",
164
187
  signedIn: null
165
188
  };
166
- if (yield* Effect.tryPromise({
167
- try: async () => {
168
- return await queryTotpVerifiedByUserId(ctx, result.userId) !== null;
169
- },
170
- catch: (error) => asConvexError(error, "INTERNAL_ERROR", "Failed to load TOTP enrollment.")
171
- })) {
172
- yield* Effect.tryPromise({
173
- try: () => callSignIn(ctx, {
189
+ let hasTotpEnrolled;
190
+ try {
191
+ hasTotpEnrolled = await queryTotpVerifiedByUserId(ctx, result.userId) !== null;
192
+ } catch (error) {
193
+ throw asConvexError(error, "INTERNAL_ERROR", "Failed to load TOTP enrollment.");
194
+ }
195
+ if (hasTotpEnrolled) {
196
+ try {
197
+ await callSignIn(ctx, {
174
198
  userId: result.userId,
175
199
  sessionId: result.sessionId,
176
200
  generateTokens: false
177
- }),
178
- catch: (error) => asConvexError(error, "INTERNAL_ERROR", "Failed to start TOTP sign-in.")
179
- });
180
- const verifier = yield* Effect.tryPromise({
181
- try: () => callVerifier(ctx),
182
- catch: (error) => asConvexError(error, "INTERNAL_ERROR", "Failed to create verifier.")
183
- });
184
- yield* Effect.tryPromise({
185
- try: () => callVerifierSignature(ctx, {
186
- verifier,
187
- signature: JSON.stringify({ userId: result.userId })
188
- }),
189
- catch: (error) => asConvexError(error, "INTERNAL_ERROR", "Failed to store verifier signature.")
190
- });
201
+ });
202
+ } catch (error) {
203
+ throw asConvexError(error, "INTERNAL_ERROR", "Failed to start TOTP sign-in.");
204
+ }
205
+ let verifier;
206
+ try {
207
+ verifier = await callVerifier(ctx, JSON.stringify({ userId: result.userId }));
208
+ } catch (error) {
209
+ throw asConvexError(error, "INTERNAL_ERROR", "Failed to create verifier.");
210
+ }
191
211
  return {
192
212
  kind: "totpRequired",
193
213
  verifier
194
214
  };
195
215
  }
216
+ let idsAndTokens;
217
+ try {
218
+ idsAndTokens = await callSignIn(ctx, {
219
+ userId: result.userId,
220
+ sessionId: result.sessionId,
221
+ generateTokens: options.generateTokens
222
+ });
223
+ } catch (error) {
224
+ throw asConvexError(error, "INTERNAL_ERROR", "Failed to complete sign-in.");
225
+ }
196
226
  return {
197
227
  kind: "signedIn",
198
- signedIn: yield* Effect.tryPromise({
199
- try: () => callSignIn(ctx, {
200
- userId: result.userId,
201
- sessionId: result.sessionId,
202
- generateTokens: options.generateTokens
203
- }),
204
- catch: (error) => asConvexError(error, "INTERNAL_ERROR", "Failed to complete sign-in.")
205
- })
228
+ signedIn: idsAndTokens
206
229
  };
207
- }).pipe(Effect.withSpan("convex-auth.signin.credentials"));
230
+ });
208
231
  }
209
- function handleOAuthProviderFx(ctx, provider, args, options) {
210
- return Effect.gen(function* () {
211
- if (args.params?.code !== void 0) return {
212
- kind: "signedIn",
213
- signedIn: yield* Effect.tryPromise({
214
- try: () => callVerifyCodeAndSignIn(ctx, {
232
+ async function handleOAuthProviderFx(ctx, provider, args, options) {
233
+ return withSpan(`convex-auth.signin.oauth`, { provider: provider.id }, async () => {
234
+ if (args.params?.code !== void 0) {
235
+ let result;
236
+ try {
237
+ result = await callVerifyCodeAndSignIn(ctx, {
215
238
  params: args.params,
216
239
  verifier: args.verifier,
217
240
  generateTokens: true,
218
241
  allowExtraProviders: options.allowExtraProviders
219
- }),
220
- catch: (error) => asConvexError(error, "INTERNAL_ERROR", "Failed to verify OAuth sign-in.")
221
- })
222
- };
242
+ });
243
+ } catch (error) {
244
+ throw asConvexError(error, "INTERNAL_ERROR", "Failed to verify OAuth sign-in.");
245
+ }
246
+ return {
247
+ kind: "signedIn",
248
+ signedIn: result
249
+ };
250
+ }
223
251
  const redirect = new URL((readConfigSync(envOptionalString("CUSTOM_AUTH_SITE_URL")) ?? requireEnv("CONVEX_SITE_URL")) + `/api/auth/signin/${provider.id}`);
224
- const verifier = yield* Effect.tryPromise({
225
- try: () => callVerifier(ctx),
226
- catch: (error) => asConvexError(error, "INTERNAL_ERROR", "Failed to create verifier.")
227
- });
252
+ let verifier;
253
+ try {
254
+ verifier = await callVerifier(ctx);
255
+ } catch (error) {
256
+ throw asConvexError(error, "INTERNAL_ERROR", "Failed to create verifier.");
257
+ }
228
258
  redirect.searchParams.set("code", verifier);
229
259
  if (args.params?.redirectTo !== void 0) {
230
- if (typeof args.params.redirectTo !== "string") return yield* Effect.fail(toConvexError(authFlowError("INVALID_REDIRECT", `Expected \`redirectTo\` to be a string, got ${describeUnknown(args.params.redirectTo)}`)));
260
+ if (typeof args.params.redirectTo !== "string") throw toConvexError(authFlowError("INVALID_REDIRECT", `Expected \`redirectTo\` to be a string, got ${describeUnknown(args.params.redirectTo)}`));
231
261
  redirect.searchParams.set("redirectTo", args.params.redirectTo);
232
262
  }
233
263
  return {
@@ -235,27 +265,32 @@ function handleOAuthProviderFx(ctx, provider, args, options) {
235
265
  redirect: redirect.toString(),
236
266
  verifier
237
267
  };
238
- }).pipe(Effect.withSpan(`convex-auth.signin.oauth`, { attributes: { provider: provider.id } }));
268
+ });
239
269
  }
240
- function handleSsoProviderFx(ctx, args, options) {
241
- return Effect.gen(function* () {
270
+ async function handleSsoProviderFx(ctx, args, options) {
271
+ return withSpan("convex-auth.signin.sso", {}, async () => {
242
272
  const normalizedParams = normalizeVerificationParams(args.params);
243
273
  const connectionId = normalizedParams.connectionId;
244
- if (!connectionId || typeof connectionId !== "string") return yield* Effect.fail(toConvexError(authFlowError("SIGN_IN_MISSING_PARAMS", "connectionId is required for SSO sign-in.")));
245
- const protocol = (normalizedParams.protocol === "oidc" || normalizedParams.protocol === "saml" ? normalizedParams.protocol : void 0) ?? (options.resolveSsoProtocol ? yield* Effect.tryPromise({
246
- try: () => options.resolveSsoProtocol(ctx, connectionId),
247
- catch: (error) => asConvexError(error, "INTERNAL_ERROR", "Failed to resolve SSO protocol.")
248
- }) : "oidc");
274
+ if (!connectionId || typeof connectionId !== "string") throw toConvexError(authFlowError("SIGN_IN_MISSING_PARAMS", "connectionId is required for SSO sign-in."));
275
+ let protocol = (normalizedParams.protocol === "oidc" || normalizedParams.protocol === "saml" ? normalizedParams.protocol : void 0) ?? (options.resolveSsoProtocol ? await (async () => {
276
+ try {
277
+ return await options.resolveSsoProtocol(ctx, connectionId);
278
+ } catch (error) {
279
+ throw asConvexError(error, "INTERNAL_ERROR", "Failed to resolve SSO protocol.");
280
+ }
281
+ })() : "oidc");
249
282
  log("DEBUG", "[group-sso] signin:resolved", {
250
283
  connectionId,
251
284
  protocol,
252
285
  redirectTo: typeof args.params?.redirectTo === "string" ? args.params.redirectTo : void 0
253
286
  });
254
- if (protocol !== "oidc" && protocol !== "saml") return yield* Effect.fail(toConvexError(authFlowError("SIGN_IN_MISSING_PARAMS", `Invalid SSO protocol: ${protocol}. Expected "oidc" or "saml".`)));
255
- const verifier = yield* Effect.tryPromise({
256
- try: () => callVerifier(ctx),
257
- catch: (error) => asConvexError(error, "INTERNAL_ERROR", "Failed to create verifier.")
258
- });
287
+ if (protocol !== "oidc" && protocol !== "saml") throw toConvexError(authFlowError("SIGN_IN_MISSING_PARAMS", `Invalid SSO protocol: ${protocol}. Expected "oidc" or "saml".`));
288
+ let verifier;
289
+ try {
290
+ verifier = await callVerifier(ctx);
291
+ } catch (error) {
292
+ throw asConvexError(error, "INTERNAL_ERROR", "Failed to create verifier.");
293
+ }
259
294
  const siteUrl = readConfigSync(envOptionalString("CUSTOM_AUTH_SITE_URL")) ?? requireEnv("CONVEX_SITE_URL");
260
295
  const redirect = new URL(`${siteUrl}/api/auth/connections/${connectionId}/${protocol}/signin`);
261
296
  redirect.searchParams.set("code", verifier);
@@ -271,7 +306,7 @@ function handleSsoProviderFx(ctx, args, options) {
271
306
  redirect: redirect.toString(),
272
307
  verifier
273
308
  };
274
- }).pipe(Effect.withSpan("convex-auth.signin.sso"));
309
+ });
275
310
  }
276
311
 
277
312
  //#endregion
@@ -1,11 +1,9 @@
1
+ import { ComponentCtx, ComponentReadCtx } from "../componentContext.js";
1
2
  import { ConvexAuthMaterializedConfig, GroupConnectionDeprovisionMode, GroupConnectionPolicy, GroupConnectionPolicyPatch, OIDCClaimMapping } from "../types.js";
2
3
  import { AuditEventRecord, ConnectionDomainRecord, GroupConnectionDomainLookupRecord, GroupConnectionListResult, GroupConnectionRecord, ScimConfigRecord, ScimIdentityRecord, WebhookDeliveryRecord, WebhookEndpointRecord } from "../contract.js";
3
- import * as convex_server320 from "convex/server";
4
4
  import { GenericActionCtx, GenericDataModel } from "convex/server";
5
5
 
6
6
  //#region src/server/sso/domain.d.ts
7
- type ComponentCtx = Pick<GenericActionCtx<GenericDataModel>, "runQuery" | "runMutation">;
8
- type ComponentReadCtx = Pick<GenericActionCtx<GenericDataModel>, "runQuery">;
9
7
  type DomainDeps = {
10
8
  config: ConvexAuthMaterializedConfig & {
11
9
  extraProviders?: unknown[];
@@ -309,16 +307,9 @@ declare function createGroupConnectionDomain<TDeps extends DomainDeps>(deps: TDe
309
307
  }>;
310
308
  };
311
309
  policy: {
312
- get: (ctx: {
313
- runQuery: <Query extends convex_server320.FunctionReference<"query", "public" | "internal">>(query: Query, ...args: convex_server320.OptionalRestArgs<Query>) => Promise<convex_server320.FunctionReturnType<Query>>;
314
- }, groupId: string) => Promise<GroupConnectionPolicy>;
315
- update: (ctx: {
316
- runQuery: <Query extends convex_server320.FunctionReference<"query", "public" | "internal">>(query: Query, ...args: convex_server320.OptionalRestArgs<Query>) => Promise<convex_server320.FunctionReturnType<Query>>;
317
- runMutation: <Mutation extends convex_server320.FunctionReference<"mutation", "public" | "internal">>(mutation: Mutation, ...args: convex_server320.OptionalRestArgs<Mutation>) => Promise<convex_server320.FunctionReturnType<Mutation>>;
318
- }, groupId: string, patch: GroupConnectionPolicyPatch) => Promise<GroupConnectionPolicy>;
319
- validate: (ctx: {
320
- runQuery: <Query extends convex_server320.FunctionReference<"query", "public" | "internal">>(query: Query, ...args: convex_server320.OptionalRestArgs<Query>) => Promise<convex_server320.FunctionReturnType<Query>>;
321
- }, groupId: string) => Promise<{
310
+ get: (ctx: ComponentReadCtx, groupId: string) => Promise<GroupConnectionPolicy>;
311
+ update: (ctx: ComponentCtx, groupId: string, patch: GroupConnectionPolicyPatch) => Promise<GroupConnectionPolicy>;
312
+ validate: (ctx: ComponentReadCtx, groupId: string) => Promise<{
322
313
  ok: boolean;
323
314
  groupId: string;
324
315
  checks: {
@@ -429,10 +420,7 @@ declare function createGroupConnectionDomain<TDeps extends DomainDeps>(deps: TDe
429
420
  }>;
430
421
  };
431
422
  scim: {
432
- configure: (ctx: {
433
- runQuery: <Query extends convex_server320.FunctionReference<"query", "public" | "internal">>(query: Query, ...args: convex_server320.OptionalRestArgs<Query>) => Promise<convex_server320.FunctionReturnType<Query>>;
434
- runMutation: <Mutation extends convex_server320.FunctionReference<"mutation", "public" | "internal">>(mutation: Mutation, ...args: convex_server320.OptionalRestArgs<Mutation>) => Promise<convex_server320.FunctionReturnType<Mutation>>;
435
- }, data: {
423
+ configure: (ctx: ComponentCtx, data: {
436
424
  connectionId: string;
437
425
  status?: "draft" | "active" | "disabled";
438
426
  security?: {
@@ -459,9 +447,7 @@ declare function createGroupConnectionDomain<TDeps extends DomainDeps>(deps: TDe
459
447
  basePath: string;
460
448
  token: string;
461
449
  }>;
462
- get: (ctx: {
463
- runQuery: <Query extends convex_server320.FunctionReference<"query", "public" | "internal">>(query: Query, ...args: convex_server320.OptionalRestArgs<Query>) => Promise<convex_server320.FunctionReturnType<Query>>;
464
- }, connectionId: string) => Promise<{
450
+ get: (ctx: ComponentReadCtx, connectionId: string) => Promise<{
465
451
  security: {
466
452
  maxRequestSize?: number;
467
453
  } | undefined;
@@ -490,9 +476,7 @@ declare function createGroupConnectionDomain<TDeps extends DomainDeps>(deps: TDe
490
476
  lastRotatedAt?: number;
491
477
  extend?: unknown;
492
478
  } | null>;
493
- status: (ctx: {
494
- runQuery: <Query extends convex_server320.FunctionReference<"query", "public" | "internal">>(query: Query, ...args: convex_server320.OptionalRestArgs<Query>) => Promise<convex_server320.FunctionReturnType<Query>>;
495
- }, connectionId: string) => Promise<{
479
+ status: (ctx: ComponentReadCtx, connectionId: string) => Promise<{
496
480
  connectionId: string;
497
481
  configured: boolean;
498
482
  ready: boolean;
@@ -516,12 +500,8 @@ declare function createGroupConnectionDomain<TDeps extends DomainDeps>(deps: TDe
516
500
  etag: boolean;
517
501
  } | undefined;
518
502
  }>;
519
- getConfigByToken: (ctx: {
520
- runQuery: <Query extends convex_server320.FunctionReference<"query", "public" | "internal">>(query: Query, ...args: convex_server320.OptionalRestArgs<Query>) => Promise<convex_server320.FunctionReturnType<Query>>;
521
- }, token: string) => Promise<ScimConfigRecord | null>;
522
- validate: (ctx: {
523
- runQuery: <Query extends convex_server320.FunctionReference<"query", "public" | "internal">>(query: Query, ...args: convex_server320.OptionalRestArgs<Query>) => Promise<convex_server320.FunctionReturnType<Query>>;
524
- }, connectionId: string) => Promise<{
503
+ getConfigByToken: (ctx: ComponentReadCtx, token: string) => Promise<ScimConfigRecord | null>;
504
+ validate: (ctx: ComponentReadCtx, connectionId: string) => Promise<{
525
505
  ok: boolean;
526
506
  connectionId: string;
527
507
  checks: {
@@ -553,17 +533,12 @@ declare function createGroupConnectionDomain<TDeps extends DomainDeps>(deps: TDe
553
533
  }[];
554
534
  }>;
555
535
  identity: {
556
- get: (ctx: {
557
- runQuery: <Query extends convex_server320.FunctionReference<"query", "public" | "internal">>(query: Query, ...args: convex_server320.OptionalRestArgs<Query>) => Promise<convex_server320.FunctionReturnType<Query>>;
558
- }, data: {
536
+ get: (ctx: ComponentReadCtx, data: {
559
537
  connectionId: string;
560
538
  resourceType: "user" | "group";
561
539
  externalId: string;
562
540
  }) => Promise<ScimIdentityRecord | null>;
563
- upsert: (ctx: {
564
- runQuery: <Query extends convex_server320.FunctionReference<"query", "public" | "internal">>(query: Query, ...args: convex_server320.OptionalRestArgs<Query>) => Promise<convex_server320.FunctionReturnType<Query>>;
565
- runMutation: <Mutation extends convex_server320.FunctionReference<"mutation", "public" | "internal">>(mutation: Mutation, ...args: convex_server320.OptionalRestArgs<Mutation>) => Promise<convex_server320.FunctionReturnType<Mutation>>;
566
- }, data: {
541
+ upsert: (ctx: ComponentCtx, data: {
567
542
  connectionId: string;
568
543
  groupId: string;
569
544
  resourceType: "user" | "group";
@@ -597,13 +572,8 @@ declare function createGroupConnectionDomain<TDeps extends DomainDeps>(deps: TDe
597
572
  };
598
573
  webhook: {
599
574
  endpoint: {
600
- get: (ctx: {
601
- runQuery: <Query extends convex_server320.FunctionReference<"query", "public" | "internal">>(query: Query, ...args: convex_server320.OptionalRestArgs<Query>) => Promise<convex_server320.FunctionReturnType<Query>>;
602
- }, endpointId: string) => Promise<WebhookEndpointRecord | null>;
603
- create: (ctx: {
604
- runQuery: <Query extends convex_server320.FunctionReference<"query", "public" | "internal">>(query: Query, ...args: convex_server320.OptionalRestArgs<Query>) => Promise<convex_server320.FunctionReturnType<Query>>;
605
- runMutation: <Mutation extends convex_server320.FunctionReference<"mutation", "public" | "internal">>(mutation: Mutation, ...args: convex_server320.OptionalRestArgs<Mutation>) => Promise<convex_server320.FunctionReturnType<Mutation>>;
606
- }, data: {
575
+ get: (ctx: ComponentReadCtx, endpointId: string) => Promise<WebhookEndpointRecord | null>;
576
+ create: (ctx: ComponentCtx, data: {
607
577
  connectionId: string;
608
578
  url: string;
609
579
  secret: string;
@@ -612,43 +582,25 @@ declare function createGroupConnectionDomain<TDeps extends DomainDeps>(deps: TDe
612
582
  }) => Promise<{
613
583
  endpointId: string;
614
584
  }>;
615
- list: (ctx: {
616
- runQuery: <Query extends convex_server320.FunctionReference<"query", "public" | "internal">>(query: Query, ...args: convex_server320.OptionalRestArgs<Query>) => Promise<convex_server320.FunctionReturnType<Query>>;
617
- }, connectionId: string) => Promise<WebhookEndpointRecord[]>;
618
- disable: (ctx: {
619
- runQuery: <Query extends convex_server320.FunctionReference<"query", "public" | "internal">>(query: Query, ...args: convex_server320.OptionalRestArgs<Query>) => Promise<convex_server320.FunctionReturnType<Query>>;
620
- runMutation: <Mutation extends convex_server320.FunctionReference<"mutation", "public" | "internal">>(mutation: Mutation, ...args: convex_server320.OptionalRestArgs<Mutation>) => Promise<convex_server320.FunctionReturnType<Mutation>>;
621
- }, endpointId: string) => Promise<{
585
+ list: (ctx: ComponentReadCtx, connectionId: string) => Promise<WebhookEndpointRecord[]>;
586
+ disable: (ctx: ComponentCtx, endpointId: string) => Promise<{
622
587
  endpointId: string;
623
588
  }>;
624
589
  };
625
- emit: (ctx: {
626
- runQuery: <Query extends convex_server320.FunctionReference<"query", "public" | "internal">>(query: Query, ...args: convex_server320.OptionalRestArgs<Query>) => Promise<convex_server320.FunctionReturnType<Query>>;
627
- runMutation: <Mutation extends convex_server320.FunctionReference<"mutation", "public" | "internal">>(mutation: Mutation, ...args: convex_server320.OptionalRestArgs<Mutation>) => Promise<convex_server320.FunctionReturnType<Mutation>>;
628
- }, data: {
590
+ emit: (ctx: ComponentCtx, data: {
629
591
  connectionId: string;
630
592
  eventType: string;
631
593
  payload: Record<string, unknown>;
632
594
  auditEventId?: string;
633
595
  }) => Promise<void>;
634
596
  delivery: {
635
- list: (ctx: {
636
- runQuery: <Query extends convex_server320.FunctionReference<"query", "public" | "internal">>(query: Query, ...args: convex_server320.OptionalRestArgs<Query>) => Promise<convex_server320.FunctionReturnType<Query>>;
637
- }, data: {
597
+ list: (ctx: ComponentReadCtx, data: {
638
598
  connectionId: string;
639
599
  limit?: number;
640
600
  }) => Promise<WebhookDeliveryRecord[]>;
641
- listReady: (ctx: {
642
- runQuery: <Query extends convex_server320.FunctionReference<"query", "public" | "internal">>(query: Query, ...args: convex_server320.OptionalRestArgs<Query>) => Promise<convex_server320.FunctionReturnType<Query>>;
643
- }, limit?: number) => Promise<WebhookDeliveryRecord[]>;
644
- markDelivered: (ctx: {
645
- runQuery: <Query extends convex_server320.FunctionReference<"query", "public" | "internal">>(query: Query, ...args: convex_server320.OptionalRestArgs<Query>) => Promise<convex_server320.FunctionReturnType<Query>>;
646
- runMutation: <Mutation extends convex_server320.FunctionReference<"mutation", "public" | "internal">>(mutation: Mutation, ...args: convex_server320.OptionalRestArgs<Mutation>) => Promise<convex_server320.FunctionReturnType<Mutation>>;
647
- }, deliveryId: string, responseStatus?: number) => Promise<void>;
648
- markFailed: (ctx: {
649
- runQuery: <Query extends convex_server320.FunctionReference<"query", "public" | "internal">>(query: Query, ...args: convex_server320.OptionalRestArgs<Query>) => Promise<convex_server320.FunctionReturnType<Query>>;
650
- runMutation: <Mutation extends convex_server320.FunctionReference<"mutation", "public" | "internal">>(mutation: Mutation, ...args: convex_server320.OptionalRestArgs<Mutation>) => Promise<convex_server320.FunctionReturnType<Mutation>>;
651
- }, deliveryId: string, data: {
601
+ listReady: (ctx: ComponentReadCtx, limit?: number) => Promise<WebhookDeliveryRecord[]>;
602
+ markDelivered: (ctx: ComponentCtx, deliveryId: string, responseStatus?: number) => Promise<void>;
603
+ markFailed: (ctx: ComponentCtx, deliveryId: string, data: {
652
604
  attemptCount: number;
653
605
  responseStatus?: number;
654
606
  error?: string;