@robelest/convex-auth 0.0.2-preview.1 → 0.0.2-preview.2

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 (67) hide show
  1. package/dist/client/index.d.ts +84 -30
  2. package/dist/client/index.d.ts.map +1 -1
  3. package/dist/client/index.js +259 -59
  4. package/dist/client/index.js.map +1 -1
  5. package/dist/component/index.d.ts +2 -2
  6. package/dist/component/index.d.ts.map +1 -1
  7. package/dist/component/index.js +2 -2
  8. package/dist/component/index.js.map +1 -1
  9. package/dist/providers/{Anonymous.d.ts → anonymous.d.ts} +8 -8
  10. package/dist/providers/{Anonymous.d.ts.map → anonymous.d.ts.map} +1 -1
  11. package/dist/providers/{Anonymous.js → anonymous.js} +9 -10
  12. package/dist/providers/anonymous.js.map +1 -0
  13. package/dist/providers/{ConvexCredentials.d.ts → credentials.d.ts} +11 -11
  14. package/dist/providers/credentials.d.ts.map +1 -0
  15. package/dist/providers/{ConvexCredentials.js → credentials.js} +8 -8
  16. package/dist/providers/credentials.js.map +1 -0
  17. package/dist/providers/{Email.d.ts → email.d.ts} +6 -6
  18. package/dist/providers/email.d.ts.map +1 -0
  19. package/dist/providers/{Email.js → email.js} +6 -6
  20. package/dist/providers/email.js.map +1 -0
  21. package/dist/providers/{Password.d.ts → password.d.ts} +10 -10
  22. package/dist/providers/{Password.d.ts.map → password.d.ts.map} +1 -1
  23. package/dist/providers/{Password.js → password.js} +19 -20
  24. package/dist/providers/password.js.map +1 -0
  25. package/dist/providers/{Phone.d.ts → phone.d.ts} +3 -3
  26. package/dist/providers/{Phone.d.ts.map → phone.d.ts.map} +1 -1
  27. package/dist/providers/{Phone.js → phone.js} +3 -3
  28. package/dist/providers/{Phone.js.map → phone.js.map} +1 -1
  29. package/dist/server/implementation/index.d.ts +73 -159
  30. package/dist/server/implementation/index.d.ts.map +1 -1
  31. package/dist/server/implementation/index.js +74 -100
  32. package/dist/server/implementation/index.js.map +1 -1
  33. package/dist/server/implementation/sessions.d.ts +2 -20
  34. package/dist/server/implementation/sessions.d.ts.map +1 -1
  35. package/dist/server/implementation/sessions.js +2 -20
  36. package/dist/server/implementation/sessions.js.map +1 -1
  37. package/dist/server/index.d.ts +18 -0
  38. package/dist/server/index.d.ts.map +1 -1
  39. package/dist/server/index.js +255 -0
  40. package/dist/server/index.js.map +1 -1
  41. package/dist/server/provider_utils.d.ts.map +1 -1
  42. package/dist/server/types.d.ts +70 -9
  43. package/dist/server/types.d.ts.map +1 -1
  44. package/package.json +3 -6
  45. package/src/client/index.ts +347 -110
  46. package/src/component/index.ts +1 -8
  47. package/src/providers/{Anonymous.ts → anonymous.ts} +10 -11
  48. package/src/providers/{ConvexCredentials.ts → credentials.ts} +11 -11
  49. package/src/providers/{Email.ts → email.ts} +5 -5
  50. package/src/providers/{Password.ts → password.ts} +22 -27
  51. package/src/providers/{Phone.ts → phone.ts} +2 -2
  52. package/src/server/implementation/index.ts +119 -231
  53. package/src/server/implementation/sessions.ts +2 -20
  54. package/src/server/index.ts +373 -0
  55. package/src/server/types.ts +95 -8
  56. package/dist/providers/Anonymous.js.map +0 -1
  57. package/dist/providers/ConvexCredentials.d.ts.map +0 -1
  58. package/dist/providers/ConvexCredentials.js.map +0 -1
  59. package/dist/providers/Email.d.ts.map +0 -1
  60. package/dist/providers/Email.js.map +0 -1
  61. package/dist/providers/Password.js.map +0 -1
  62. package/providers/Anonymous/package.json +0 -6
  63. package/providers/ConvexCredentials/package.json +0 -6
  64. package/providers/Email/package.json +0 -6
  65. package/providers/Password/package.json +0 -6
  66. package/providers/Phone/package.json +0 -6
  67. package/server/package.json +0 -6
@@ -1,19 +1,17 @@
1
1
  import { OAuth2Config, OAuthConfig } from "@auth/core/providers";
2
2
  import {
3
3
  Auth,
4
- DocumentByName,
5
4
  GenericActionCtx,
6
5
  GenericDataModel,
7
6
  HttpRouter,
8
- WithoutSystemFields,
9
7
  actionGeneric,
10
8
  httpActionGeneric,
11
9
  internalMutationGeneric,
12
10
  } from "convex/server";
13
- import { ConvexError, GenericId, Value, v } from "convex/values";
11
+ import { ConvexError, GenericId, v } from "convex/values";
14
12
  import { parse as parseCookies, serialize as serializeCookie } from "cookie";
15
13
  import { redirectToParamCookie, useRedirectToParam } from "../cookies.js";
16
- import { FunctionReferenceFromExport, GenericDoc } from "../convex_types.js";
14
+ import { FunctionReferenceFromExport } from "../convex_types.js";
17
15
  import {
18
16
  configDefaults,
19
17
  listAvailableProviders,
@@ -22,7 +20,6 @@ import {
22
20
  import {
23
21
  AuthProviderConfig,
24
22
  ConvexAuthConfig,
25
- GenericActionCtxWithAuthConfig,
26
23
  } from "../types.js";
27
24
  import { requireEnv } from "../utils.js";
28
25
  import { ActionCtx, MutationCtx, Tokens } from "./types.js";
@@ -53,7 +50,6 @@ import {
53
50
  oAuthConfigToInternalProvider,
54
51
  } from "../oauth/convexAuth.js";
55
52
  import { handleOAuth } from "../oauth/callback.js";
56
- export { getAuthSessionId } from "./sessions.js";
57
53
 
58
54
  /**
59
55
  * The type of the signIn Convex Action returned from the auth() helper.
@@ -118,15 +114,25 @@ export function Auth(config_: ConvexAuthConfig) {
118
114
  }
119
115
  return provider;
120
116
  };
121
- const enrichCtx = <DataModel extends GenericDataModel>(
122
- ctx: GenericActionCtx<DataModel>,
123
- ) => ({ ...ctx, auth: { ...ctx.auth, config } });
124
117
  type ComponentCtx = Pick<
125
118
  GenericActionCtx<GenericDataModel>,
126
119
  "runQuery" | "runMutation"
127
120
  >;
128
121
  type ComponentReadCtx = Pick<GenericActionCtx<GenericDataModel>, "runQuery">;
129
122
  type ComponentAuthReadCtx = ComponentReadCtx & { auth: Auth };
123
+ type AccountCredentials = { id: string; secret?: string };
124
+ type CreateAccountArgs = {
125
+ provider: string;
126
+ account: AccountCredentials;
127
+ profile: Record<string, unknown>;
128
+ shouldLinkViaEmail?: boolean;
129
+ shouldLinkViaPhone?: boolean;
130
+ };
131
+ type RetrieveAccountArgs = { provider: string; account: AccountCredentials };
132
+ type UpdateAccountCredentialsArgs = {
133
+ provider: string;
134
+ account: { id: string; secret: string };
135
+ };
130
136
 
131
137
  const auth = {
132
138
  user: {
@@ -198,6 +204,97 @@ export function Auth(config_: ConvexAuthConfig) {
198
204
  },
199
205
  },
200
206
  },
207
+ session: {
208
+ /**
209
+ * Get the current session ID from the auth context, or `null` if
210
+ * not signed in.
211
+ */
212
+ current: async (ctx: { auth: Auth }) => {
213
+ const identity = await ctx.auth.getUserIdentity();
214
+ if (identity === null) {
215
+ return null;
216
+ }
217
+ const [, sessionId] = identity.subject.split(TOKEN_SUB_CLAIM_DIVIDER);
218
+ return sessionId as GenericId<"session">;
219
+ },
220
+ /**
221
+ * Invalidate sessions for a user, optionally preserving specific sessions.
222
+ */
223
+ invalidate: async <DataModel extends GenericDataModel>(
224
+ ctx: GenericActionCtx<DataModel>,
225
+ args: {
226
+ userId: GenericId<"user">;
227
+ except?: GenericId<"session">[];
228
+ },
229
+ ): Promise<void> => {
230
+ const actionCtx = ctx as unknown as ActionCtx;
231
+ return await callInvalidateSessions(actionCtx, args);
232
+ },
233
+ },
234
+ account: {
235
+ /**
236
+ * Create an account and user for a credentials provider.
237
+ */
238
+ create: async <DataModel extends GenericDataModel>(
239
+ ctx: GenericActionCtx<DataModel>,
240
+ args: CreateAccountArgs,
241
+ ) => {
242
+ const actionCtx = ctx as unknown as ActionCtx;
243
+ return await callCreateAccountFromCredentials(actionCtx, args as any);
244
+ },
245
+ /**
246
+ * Retrieve an account and user for a credentials provider.
247
+ */
248
+ get: async <DataModel extends GenericDataModel>(
249
+ ctx: GenericActionCtx<DataModel>,
250
+ args: RetrieveAccountArgs,
251
+ ) => {
252
+ const actionCtx = ctx as unknown as ActionCtx;
253
+ const result = await callRetreiveAccountWithCredentials(actionCtx, args);
254
+ if (typeof result === "string") {
255
+ throw new Error(result);
256
+ }
257
+ return result;
258
+ },
259
+ /**
260
+ * Update credentials for an existing account.
261
+ */
262
+ updateCredentials: async <DataModel extends GenericDataModel>(
263
+ ctx: GenericActionCtx<DataModel>,
264
+ args: UpdateAccountCredentialsArgs,
265
+ ): Promise<void> => {
266
+ const actionCtx = ctx as unknown as ActionCtx;
267
+ return await callModifyAccount(actionCtx, args);
268
+ },
269
+ },
270
+ provider: {
271
+ /**
272
+ * Sign in via another provider, typically from a credentials flow.
273
+ */
274
+ signIn: async <DataModel extends GenericDataModel>(
275
+ ctx: GenericActionCtx<DataModel>,
276
+ provider: AuthProviderConfig,
277
+ args: {
278
+ accountId?: GenericId<"account">;
279
+ params?: Record<string, unknown>;
280
+ },
281
+ ) => {
282
+ const result = await signInImpl(
283
+ enrichCtx(ctx),
284
+ materializeProvider(provider),
285
+ args as any,
286
+ {
287
+ generateTokens: false,
288
+ allowExtraProviders: true,
289
+ },
290
+ );
291
+ return result.kind === "signedIn"
292
+ ? result.signedIn !== null
293
+ ? { userId: result.signedIn.userId, sessionId: result.signedIn.sessionId }
294
+ : null
295
+ : null;
296
+ },
297
+ },
201
298
  /**
202
299
  * Hierarchical group management. Groups can nest arbitrarily deep
203
300
  * via `parentGroupId`. A root group has no parent.
@@ -655,6 +752,19 @@ export function Auth(config_: ConvexAuthConfig) {
655
752
  }
656
753
  },
657
754
  };
755
+ const enrichCtx = <DataModel extends GenericDataModel>(
756
+ ctx: GenericActionCtx<DataModel>,
757
+ ) => ({
758
+ ...ctx,
759
+ auth: {
760
+ ...ctx.auth,
761
+ config,
762
+ account: auth.account,
763
+ session: auth.session,
764
+ provider: auth.provider,
765
+ },
766
+ });
767
+
658
768
  return {
659
769
  /**
660
770
  * Helper for configuring HTTP actions.
@@ -732,228 +842,6 @@ export function Auth(config_: ConvexAuthConfig) {
732
842
  };
733
843
  }
734
844
 
735
- /**
736
- * Return the currently signed-in user's ID.
737
- *
738
- * ```ts filename="convex/myFunctions.tsx"
739
- * import { mutation } from "./_generated/server";
740
- * import { getAuthUserId } from "@robelest/convex-auth/component";
741
- *
742
- * export const doSomething = mutation({
743
- * args: {/* ... *\/},
744
- * handler: async (ctx, args) => {
745
- * const userId = await getAuthUserId(ctx);
746
- * if (userId === null) {
747
- * throw new Error("Client is not authenticated!")
748
- * }
749
- * const user = await ctx.db.get(userId);
750
- * // ...
751
- * },
752
- * });
753
- * ```
754
- *
755
- * @param ctx query, mutation or action `ctx`
756
- * @returns the user ID or `null` if the client isn't authenticated
757
- */
758
- export async function getAuthUserId(ctx: { auth: Auth }) {
759
- const identity = await ctx.auth.getUserIdentity();
760
- if (identity === null) {
761
- return null;
762
- }
763
- const [userId] = identity.subject.split(TOKEN_SUB_CLAIM_DIVIDER);
764
- return userId as GenericId<"user">;
765
- }
766
-
767
- /**
768
- * Use this function from a
769
- * [`ConvexCredentials`](https://labs.convex.dev/auth/api_reference/providers/ConvexCredentials)
770
- * provider to create an account and a user with a unique account "id" (OAuth
771
- * provider ID, email address, phone number, username etc.).
772
- *
773
- * @returns user ID if it successfully creates the account
774
- * or throws an error.
775
- */
776
- export async function createAccount<
777
- DataModel extends GenericDataModel = GenericDataModel,
778
- >(
779
- ctx: GenericActionCtx<DataModel>,
780
- args: {
781
- /**
782
- * The provider ID (like "password"), used to disambiguate accounts.
783
- *
784
- * It is also used to configure account secret hashing via the provider's
785
- * `crypto` option.
786
- */
787
- provider: string;
788
- account: {
789
- /**
790
- * The unique external ID for the account, for example email address.
791
- */
792
- id: string;
793
- /**
794
- * The secret credential to store for this account, if given.
795
- */
796
- secret?: string;
797
- };
798
- /**
799
- * The profile data to store for the user.
800
- * These must fit the `users` table schema.
801
- */
802
- profile: WithoutSystemFields<DocumentByName<DataModel, "user">>;
803
- /**
804
- * If `true`, the account will be linked to an existing user
805
- * with the same verified email address.
806
- * This is only safe if the returned account's email is verified
807
- * before the user is allowed to sign in with it.
808
- */
809
- shouldLinkViaEmail?: boolean;
810
- /**
811
- * If `true`, the account will be linked to an existing user
812
- * with the same verified phone number.
813
- * This is only safe if the returned account's phone is verified
814
- * before the user is allowed to sign in with it.
815
- */
816
- shouldLinkViaPhone?: boolean;
817
- },
818
- ): Promise<{
819
- account: GenericDoc<DataModel, "account">;
820
- user: GenericDoc<DataModel, "user">;
821
- }> {
822
- const actionCtx = ctx as unknown as ActionCtx;
823
- return (await callCreateAccountFromCredentials(
824
- actionCtx,
825
- args as any,
826
- )) as any;
827
- }
828
-
829
- /**
830
- * Use this function from a
831
- * [`ConvexCredentials`](https://labs.convex.dev/auth/api_reference/providers/ConvexCredentials)
832
- * provider to retrieve a user given the account provider ID and
833
- * the provider-specific account ID.
834
- *
835
- * @returns the retrieved user document, or `null` if there is no account
836
- * for given account ID or throws if the provided
837
- * secret does not match.
838
- */
839
- export async function retrieveAccount<
840
- DataModel extends GenericDataModel = GenericDataModel,
841
- >(
842
- ctx: GenericActionCtx<DataModel>,
843
- args: {
844
- /**
845
- * The provider ID (like "password"), used to disambiguate accounts.
846
- *
847
- * It is also used to configure account secret hashing via the provider's
848
- * `crypto` option.
849
- */
850
- provider: string;
851
- account: {
852
- /**
853
- * The unique external ID for the account, for example email address.
854
- */
855
- id: string;
856
- /**
857
- * The secret that should match the stored credential, if given.
858
- */
859
- secret?: string;
860
- };
861
- },
862
- ): Promise<{
863
- account: GenericDoc<DataModel, "account">;
864
- user: GenericDoc<DataModel, "user">;
865
- }> {
866
- const actionCtx = ctx as unknown as ActionCtx;
867
- const result = await callRetreiveAccountWithCredentials(actionCtx, args);
868
- if (typeof result === "string") {
869
- throw new Error(result);
870
- }
871
- return result as any;
872
- }
873
-
874
- /**
875
- * Use this function to modify the account credentials
876
- * from a [`ConvexCredentials`](https://labs.convex.dev/auth/api_reference/providers/ConvexCredentials)
877
- * provider.
878
- */
879
- export async function modifyAccountCredentials<
880
- DataModel extends GenericDataModel = GenericDataModel,
881
- >(
882
- ctx: GenericActionCtx<DataModel>,
883
- args: {
884
- /**
885
- * The provider ID (like "password"), used to disambiguate accounts.
886
- *
887
- * It is also used to configure account secret hashing via the `crypto` option.
888
- */
889
- provider: string;
890
- account: {
891
- /**
892
- * The unique external ID for the account, for example email address.
893
- */
894
- id: string;
895
- /**
896
- * The new secret credential to store for this account.
897
- */
898
- secret: string;
899
- };
900
- },
901
- ): Promise<void> {
902
- const actionCtx = ctx as unknown as ActionCtx;
903
- return await callModifyAccount(actionCtx, args);
904
- }
905
-
906
- /**
907
- * Use this function to invalidate existing sessions.
908
- */
909
- export async function invalidateSessions<
910
- DataModel extends GenericDataModel = GenericDataModel,
911
- >(
912
- ctx: GenericActionCtx<DataModel>,
913
- args: {
914
- userId: GenericId<"user">;
915
- except?: GenericId<"session">[];
916
- },
917
- ): Promise<void> {
918
- const actionCtx = ctx as unknown as ActionCtx;
919
- return await callInvalidateSessions(actionCtx, args);
920
- }
921
-
922
- /**
923
- * Use this function from a
924
- * [`ConvexCredentials`](https://labs.convex.dev/auth/api_reference/providers/ConvexCredentials)
925
- * provider to sign in the user via another provider (usually
926
- * for email verification on sign up or password reset).
927
- *
928
- * Returns the user ID if the sign can proceed,
929
- * or `null`.
930
- */
931
- export async function signInViaProvider<
932
- DataModel extends GenericDataModel = GenericDataModel,
933
- >(
934
- ctx: GenericActionCtxWithAuthConfig<DataModel>,
935
- provider: AuthProviderConfig,
936
- args: {
937
- accountId?: GenericId<"account">;
938
- params?: Record<string, Value | undefined>;
939
- },
940
- ) {
941
- const result = await signInImpl(
942
- ctx,
943
- materializeProvider(provider),
944
- args as any,
945
- {
946
- generateTokens: false,
947
- allowExtraProviders: true,
948
- },
949
- );
950
- return result.kind === "signedIn"
951
- ? result.signedIn !== null
952
- ? { userId: result.signedIn.userId, sessionId: result.signedIn.sessionId }
953
- : null
954
- : null;
955
- }
956
-
957
845
  function convertErrorsToResponse(
958
846
  errorStatusCode: number,
959
847
  action: (ctx: GenericActionCtx<any>, request: Request) => Promise<Response>,
@@ -110,27 +110,9 @@ export async function deleteSession(
110
110
  }
111
111
 
112
112
  /**
113
- * Return the current session ID.
113
+ * Return the current session ID from the auth identity subject.
114
114
  *
115
- * ```ts filename="convex/myFunctions.tsx"
116
- * import { mutation } from "./_generated/server";
117
- * import { getAuthSessionId } from "@robelest/convex-auth/component";
118
- *
119
- * export const doSomething = mutation({
120
- * args: {/* ... *\/},
121
- * handler: async (ctx, args) => {
122
- * const sessionId = await getAuthSessionId(ctx);
123
- * if (sessionId === null) {
124
- * throw new Error("Client is not authenticated!")
125
- * }
126
- * const session = await ctx.db.get(sessionId);
127
- * // ...
128
- * },
129
- * });
130
- * ```
131
- *
132
- * @param ctx query, mutation or action `ctx`
133
- * @returns the session ID or `null` if the client isn't authenticated
115
+ * Internal helper used by auth runtime internals and `auth.session.current`.
134
116
  */
135
117
  export async function getAuthSessionId(ctx: { auth: Auth }) {
136
118
  const identity = await ctx.auth.getUserIdentity();