@robelest/convex-auth 0.0.4-preview.32 → 0.0.4-preview.34

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 (89) hide show
  1. package/dist/component/_generated/component.d.ts +1611 -2039
  2. package/dist/component/account.js +3 -0
  3. package/dist/component/convex.config.d.ts +2 -2
  4. package/dist/component/factor/device.js +3 -0
  5. package/dist/component/factor/passkey.js +3 -0
  6. package/dist/component/factor/totp.js +3 -0
  7. package/dist/component/group/invite.js +3 -0
  8. package/dist/component/group/member.js +3 -0
  9. package/dist/component/group.js +3 -0
  10. package/dist/component/model.d.ts +342 -30
  11. package/dist/component/model.js +22 -4
  12. package/dist/component/modules.js +24 -21
  13. package/dist/component/public/factors/devices.js +37 -106
  14. package/dist/component/public/factors/passkeys.js +29 -149
  15. package/dist/component/public/factors/totp.js +32 -159
  16. package/dist/component/public/groups/core.js +19 -82
  17. package/dist/component/public/groups/invites.js +15 -104
  18. package/dist/component/public/groups/members.js +26 -149
  19. package/dist/component/public/identity/accounts.js +12 -94
  20. package/dist/component/public/identity/codes.js +13 -73
  21. package/dist/component/public/identity/sessions.js +5 -107
  22. package/dist/component/public/identity/tokens.js +13 -103
  23. package/dist/component/public/identity/users.js +188 -185
  24. package/dist/component/public/identity/verifiers.js +17 -80
  25. package/dist/component/public/security/keys.js +13 -120
  26. package/dist/component/public/security/limits.js +0 -43
  27. package/dist/component/public/sso/audit.js +0 -28
  28. package/dist/component/public/sso/core.js +31 -104
  29. package/dist/component/public/sso/domains.js +0 -71
  30. package/dist/component/public/sso/scim.js +63 -239
  31. package/dist/component/public/sso/secrets.js +0 -30
  32. package/dist/component/public/sso/webhooks.js +23 -128
  33. package/dist/component/rateLimit.js +3 -0
  34. package/dist/component/schema.d.ts +378 -342
  35. package/dist/component/schema.js +11 -1
  36. package/dist/component/session.js +3 -0
  37. package/dist/component/sso/audit.js +3 -0
  38. package/dist/component/sso/connection/domain/verification.js +3 -0
  39. package/dist/component/sso/connection/domain.js +3 -0
  40. package/dist/component/sso/connection/scim/config.js +3 -0
  41. package/dist/component/sso/connection/scim/identity.js +3 -0
  42. package/dist/component/sso/connection/secret.js +3 -0
  43. package/dist/component/sso/connection.js +3 -0
  44. package/dist/component/sso/webhook/delivery.js +3 -0
  45. package/dist/component/sso/webhook/endpoint.js +3 -0
  46. package/dist/component/token/pkce.js +3 -0
  47. package/dist/component/token/refresh.js +3 -0
  48. package/dist/component/token/verification.js +3 -0
  49. package/dist/component/user/email.js +3 -0
  50. package/dist/component/user/key.js +3 -0
  51. package/dist/component/user.js +62 -0
  52. package/dist/core/index.d.ts +131 -28
  53. package/dist/core/index.js +2 -0
  54. package/dist/model.js +391 -0
  55. package/dist/providers/credentials.d.ts +1 -1
  56. package/dist/providers/github.js +6 -0
  57. package/dist/providers/password.js +1 -2
  58. package/dist/server/auth.d.ts +73 -7
  59. package/dist/server/auth.js +4 -1
  60. package/dist/server/context.js +30 -3
  61. package/dist/server/contract.js +42 -42
  62. package/dist/server/core.js +224 -86
  63. package/dist/server/db.js +45 -37
  64. package/dist/server/facade.d.ts +39 -0
  65. package/dist/server/facade.js +16 -0
  66. package/dist/server/index.d.ts +5 -3
  67. package/dist/server/index.js +3 -1
  68. package/dist/server/mounts.d.ts +101 -101
  69. package/dist/server/mutations/credentials/signin.js +3 -7
  70. package/dist/server/mutations/oauth.js +9 -6
  71. package/dist/server/runtime.d.ts +147 -46
  72. package/dist/server/runtime.js +10 -8
  73. package/dist/server/services/group.js +9 -9
  74. package/dist/server/sso/domain.d.ts +1 -1
  75. package/dist/server/sso/domain.js +40 -40
  76. package/dist/server/sso/http.js +18 -18
  77. package/dist/server/sso/oidc.js +1 -1
  78. package/dist/server/sso/policies.js +3 -3
  79. package/dist/server/sso/policy.js +12 -4
  80. package/dist/server/sso/provision.js +9 -9
  81. package/dist/server/sso/validators.js +2 -2
  82. package/dist/server/sso/webhook.js +8 -8
  83. package/dist/server/types.d.ts +185 -124
  84. package/dist/server/types.js +29 -24
  85. package/dist/server/users.js +49 -2
  86. package/dist/server/validators.d.ts +745 -0
  87. package/dist/server/validators.js +60 -0
  88. package/package.json +1 -1
  89. package/dist/component/public.js +0 -22
@@ -14,18 +14,8 @@ import { ConvexError, v } from "convex/values";
14
14
  * @returns An array of account documents associated with the user. Each document
15
15
  * includes fields such as `provider`, `providerAccountId`, `secret`, and `extend`.
16
16
  *
17
- * @example
18
- * ```ts
19
- * const accounts = await ctx.runQuery(
20
- * component.identity.accounts.accountListByUser,
21
- * { userId: user._id },
22
- * );
23
- * for (const account of accounts) {
24
- * console.log(`Provider: ${account.provider}, ID: ${account.providerAccountId}`);
25
- * }
26
- * ```
27
17
  */
28
- const accountListByUser = query({
18
+ const accountList = query({
29
19
  args: { userId: v.id("User") },
30
20
  returns: v.array(vAccountDoc),
31
21
  handler: async (ctx, { userId }) => {
@@ -33,64 +23,21 @@ const accountListByUser = query({
33
23
  }
34
24
  });
35
25
  /**
36
- * Look up an account by its provider name and provider-specific account ID.
37
- *
38
- * Uses the `provider_account_id` index to find the unique account that matches
39
- * the given provider and external account identifier. This is the primary way
40
- * to resolve an incoming authentication event (e.g. an OAuth callback) to an
41
- * existing account in the system.
42
- *
43
- * @param args.provider - The name of the authentication provider (e.g. `"google"`, `"github"`, `"credentials"`).
44
- * @param args.providerAccountId - The unique identifier assigned to the user by the external provider.
45
- * @returns The matching account document, or `null` if no account exists for the
46
- * given provider and provider account ID combination.
47
- *
48
- * @example
49
- * ```ts
50
- * const account = await ctx.runQuery(
51
- * component.identity.accounts.accountGet,
52
- * { provider: "google", providerAccountId: "1184210396400123" },
53
- * );
54
- * if (account !== null) {
55
- * console.log(`Found account for user: ${account.userId}`);
56
- * }
57
- * ```
26
+ * Read an account by identity one function, all-optional args, unioned
27
+ * return: `{ id }` (point lookup) or `{ provider, providerAccountId }`
28
+ * (unique provider index).
58
29
  */
59
30
  const accountGet = query({
60
31
  args: {
61
- provider: v.string(),
62
- providerAccountId: v.string()
32
+ id: v.optional(v.id("Account")),
33
+ provider: v.optional(v.string()),
34
+ providerAccountId: v.optional(v.string())
63
35
  },
64
36
  returns: v.union(vAccountDoc, v.null()),
65
- handler: async (ctx, { provider, providerAccountId }) => {
66
- return await ctx.db.query("Account").withIndex("provider_account_id", (q) => q.eq("provider", provider).eq("providerAccountId", providerAccountId)).unique();
67
- }
68
- });
69
- /**
70
- * Retrieve a single account by its Convex document ID.
71
- *
72
- * Performs a direct point lookup on the `Account` table. Returns `null` if the
73
- * document has been deleted or never existed.
74
- *
75
- * @param args.accountId - The Convex document ID (`Id<"Account">`) of the account to retrieve.
76
- * @returns The account document if it exists, or `null` otherwise.
77
- *
78
- * @example
79
- * ```ts
80
- * const account = await ctx.runQuery(
81
- * component.identity.accounts.accountGetById,
82
- * { accountId: existingAccountId },
83
- * );
84
- * if (account !== null) {
85
- * console.log(`Provider: ${account.provider}`);
86
- * }
87
- * ```
88
- */
89
- const accountGetById = query({
90
- args: { accountId: v.id("Account") },
91
- returns: v.union(vAccountDoc, v.null()),
92
- handler: async (ctx, { accountId }) => {
93
- return await ctx.db.get("Account", accountId);
37
+ handler: async (ctx, args) => {
38
+ if (args.provider !== void 0 && args.providerAccountId !== void 0) return await ctx.db.query("Account").withIndex("provider_account_id", (q) => q.eq("provider", args.provider).eq("providerAccountId", args.providerAccountId)).unique();
39
+ if (args.id === void 0) return null;
40
+ return await ctx.db.get("Account", args.id);
94
41
  }
95
42
  });
96
43
  /**
@@ -108,18 +55,6 @@ const accountGetById = query({
108
55
  * @param args.extend - Optional arbitrary data to store alongside the account for application-specific needs.
109
56
  * @returns The document ID of the newly created account.
110
57
  *
111
- * @example
112
- * ```ts
113
- * const accountId = await ctx.runMutation(
114
- * component.identity.accounts.accountInsert,
115
- * {
116
- * userId: user._id,
117
- * provider: "credentials",
118
- * providerAccountId: "user@example.com",
119
- * secret: hashedPassword,
120
- * },
121
- * );
122
- * ```
123
58
  */
124
59
  const accountInsert = mutation({
125
60
  args: {
@@ -145,16 +80,6 @@ const accountInsert = mutation({
145
80
  * @param args.data - A partial object containing the fields to merge into the account document.
146
81
  * @returns `null` on success.
147
82
  *
148
- * @example
149
- * ```ts
150
- * await ctx.runMutation(
151
- * component.identity.accounts.accountPatch,
152
- * {
153
- * accountId: account._id,
154
- * data: { secret: newHashedPassword },
155
- * },
156
- * );
157
- * ```
158
83
  */
159
84
  const accountPatch = mutation({
160
85
  args: {
@@ -178,13 +103,6 @@ const accountPatch = mutation({
178
103
  * @param args.accountId - The document ID of the account to delete.
179
104
  * @returns `null` on success.
180
105
  *
181
- * @example
182
- * ```ts
183
- * await ctx.runMutation(
184
- * component.identity.accounts.accountDelete,
185
- * { accountId: account._id },
186
- * );
187
- * ```
188
106
  */
189
107
  const accountDelete = mutation({
190
108
  args: {
@@ -215,5 +133,5 @@ const accountDelete = mutation({
215
133
  });
216
134
 
217
135
  //#endregion
218
- export { accountDelete, accountGet, accountGetById, accountInsert, accountListByUser, accountPatch };
136
+ export { accountDelete, accountGet, accountInsert, accountList, accountPatch };
219
137
  //# sourceMappingURL=accounts.js.map
@@ -4,59 +4,20 @@ import { v } from "convex/values";
4
4
 
5
5
  //#region src/component/public/identity/codes.ts
6
6
  /**
7
- * Find a verification code by its associated account ID.
8
- *
9
- * Queries the `VerificationCode` table using the `account_id` index to locate
10
- * the unique verification code linked to the given account. Each account has at
11
- * most one active verification code at a time.
12
- *
13
- * @param args.accountId - The document ID of the account whose verification code should be retrieved.
14
- * @returns The verification code document if one exists for the account, or `null` otherwise.
15
- *
16
- * @example
17
- * ```ts
18
- * const code = await ctx.runQuery(
19
- * component.identity.codes.verificationCodeGetByAccountId,
20
- * { accountId: account._id },
21
- * );
22
- * if (code !== null && code.expirationTime > Date.now()) {
23
- * console.log("Active verification code exists");
24
- * }
25
- * ```
26
- */
27
- const verificationCodeGetByAccountId = query({
28
- args: { accountId: v.id("Account") },
29
- returns: v.union(vVerificationCodeDoc, v.null()),
30
- handler: async (ctx, { accountId }) => {
31
- return await ctx.db.query("VerificationCode").withIndex("account_id", (q) => q.eq("accountId", accountId)).unique();
32
- }
33
- });
34
- /**
35
- * Find a verification code by its code string value.
36
- *
37
- * Queries the `VerificationCode` table using the `code` index to locate the
38
- * unique verification code document matching the given code string. This is
39
- * the primary lookup used when a user submits an OTP or clicks a magic link.
40
- *
41
- * @param args.code - The verification code string to look up (e.g. a 6-digit OTP or a magic-link token).
42
- * @returns The verification code document if a match is found, or `null` otherwise.
43
- *
44
- * @example
45
- * ```ts
46
- * const codeDoc = await ctx.runQuery(
47
- * component.identity.codes.verificationCodeGetByCode,
48
- * { code: "482910" },
49
- * );
50
- * if (codeDoc !== null && codeDoc.expirationTime > Date.now()) {
51
- * console.log(`Code is valid for account: ${codeDoc.accountId}`);
52
- * }
53
- * ```
7
+ * Read a verification code by identity one function, all-optional
8
+ * args, unioned return: `{ accountId }` (unique per account) or
9
+ * `{ code }` (code index).
54
10
  */
55
- const verificationCodeGetByCode = query({
56
- args: { code: v.string() },
11
+ const verificationCodeGet = query({
12
+ args: {
13
+ accountId: v.optional(v.id("Account")),
14
+ code: v.optional(v.string())
15
+ },
57
16
  returns: v.union(vVerificationCodeDoc, v.null()),
58
- handler: async (ctx, { code }) => {
59
- return await ctx.db.query("VerificationCode").withIndex("code", (q) => q.eq("code", code)).first();
17
+ handler: async (ctx, args) => {
18
+ if (args.code !== void 0) return await ctx.db.query("VerificationCode").withIndex("code", (q) => q.eq("code", args.code)).first();
19
+ if (args.accountId === void 0) return null;
20
+ return await ctx.db.query("VerificationCode").withIndex("account_id", (q) => q.eq("accountId", args.accountId)).unique();
60
21
  }
61
22
  });
62
23
  /**
@@ -78,19 +39,6 @@ const verificationCodeGetByCode = query({
78
39
  * code redemption.
79
40
  * @returns The document ID of the newly created verification code.
80
41
  *
81
- * @example
82
- * ```ts
83
- * const codeId = await ctx.runMutation(
84
- * component.identity.codes.verificationCodeCreate,
85
- * {
86
- * accountId: account._id,
87
- * provider: "resend-otp",
88
- * code: "482910",
89
- * expirationTime: Date.now() + 10 * 60 * 1000, // 10 minutes
90
- * emailVerified: "alice@example.com",
91
- * },
92
- * );
93
- * ```
94
42
  */
95
43
  const verificationCodeCreate = mutation({
96
44
  args: {
@@ -117,14 +65,6 @@ const verificationCodeCreate = mutation({
117
65
  * @param args.verificationCodeId - The document ID of the verification code to delete.
118
66
  * @returns `null` on success.
119
67
  *
120
- * @example
121
- * ```ts
122
- * // Delete the code after successful verification
123
- * await ctx.runMutation(
124
- * component.identity.codes.verificationCodeDelete,
125
- * { verificationCodeId: codeDoc._id },
126
- * );
127
- * ```
128
68
  */
129
69
  const verificationCodeDelete = mutation({
130
70
  args: { verificationCodeId: v.id("VerificationCode") },
@@ -136,5 +76,5 @@ const verificationCodeDelete = mutation({
136
76
  });
137
77
 
138
78
  //#endregion
139
- export { verificationCodeCreate, verificationCodeDelete, verificationCodeGetByAccountId, verificationCodeGetByCode };
79
+ export { verificationCodeCreate, verificationCodeDelete, verificationCodeGet };
140
80
  //# sourceMappingURL=codes.js.map
@@ -1,70 +1,9 @@
1
- import { vPaginated, vSessionDoc } from "../../model.js";
1
+ import { vSessionDoc } from "../../model.js";
2
2
  import { mutation, query } from "../../functions.js";
3
3
  import { v } from "convex/values";
4
4
 
5
5
  //#region src/component/public/identity/sessions.ts
6
6
  /**
7
- * List sessions with optional filtering and cursor-based pagination.
8
- *
9
- * Supports filtering by `userId` to retrieve only sessions belonging to a
10
- * specific user. When a `userId` filter is provided, the `user_id` index is
11
- * used for efficient lookup. Results are returned as a paginated response
12
- * `{ items, nextCursor }` -- pass `nextCursor` back as `cursor` to fetch the
13
- * next page, or receive `null` when all results have been exhausted.
14
- *
15
- * @param args.where - Optional filter object. Currently supports `userId` to
16
- * restrict results to sessions for a specific user.
17
- * @param args.limit - Maximum number of sessions to return per page (1--100, default 50).
18
- * @param args.cursor - An opaque cursor string from a previous response's `nextCursor`
19
- * to continue pagination, or `null` / omitted to start from the beginning.
20
- * @param args.order - Sort direction: `"asc"` or `"desc"` (default `"desc"`).
21
- * @returns An object with `items` (array of session documents) and `nextCursor`
22
- * (`string | null`) for fetching subsequent pages.
23
- *
24
- * @example
25
- * ```ts
26
- * // List the 10 most recent sessions for a user
27
- * const page = await ctx.runQuery(
28
- * component.identity.sessions.sessionList,
29
- * { where: { userId: user._id }, limit: 10, order: "desc" },
30
- * );
31
- * for (const session of page.items) {
32
- * console.log(`Session ${session._id} expires at ${session.expirationTime}`);
33
- * }
34
- * ```
35
- */
36
- const sessionList = query({
37
- args: {
38
- where: v.optional(v.object({ userId: v.optional(v.id("User")) })),
39
- limit: v.optional(v.number()),
40
- cursor: v.optional(v.union(v.string(), v.null())),
41
- order: v.optional(v.union(v.literal("asc"), v.literal("desc")))
42
- },
43
- returns: vPaginated(vSessionDoc),
44
- handler: async (ctx, args) => {
45
- const where = args.where ?? {};
46
- const limit = Math.min(Math.max(args.limit ?? 50, 1), 100);
47
- const order = args.order ?? "desc";
48
- let q;
49
- if (where.userId !== void 0) q = ctx.db.query("Session").withIndex("user_id", (idx) => idx.eq("userId", where.userId));
50
- else q = ctx.db.query("Session");
51
- q = q.order(order);
52
- const all = await q.collect();
53
- let startIdx = 0;
54
- if (args.cursor) {
55
- const cursorIdx = all.findIndex((doc) => doc._id === args.cursor);
56
- if (cursorIdx !== -1) startIdx = cursorIdx + 1;
57
- }
58
- const page = all.slice(startIdx, startIdx + limit + 1);
59
- const hasMore = page.length > limit;
60
- const items = hasMore ? page.slice(0, limit) : page;
61
- return {
62
- items,
63
- nextCursor: hasMore ? items[items.length - 1]._id : null
64
- };
65
- }
66
- });
67
- /**
68
7
  * Create a new session for a user with a specified expiration time.
69
8
  *
70
9
  * Inserts a new document into the `Session` table, linking it to the given user.
@@ -75,16 +14,6 @@ const sessionList = query({
75
14
  * @param args.expirationTime - The Unix timestamp (in milliseconds) at which this session expires.
76
15
  * @returns The document ID of the newly created session.
77
16
  *
78
- * @example
79
- * ```ts
80
- * const sessionId = await ctx.runMutation(
81
- * component.identity.sessions.sessionCreate,
82
- * {
83
- * userId: user._id,
84
- * expirationTime: Date.now() + 30 * 24 * 60 * 60 * 1000, // 30 days
85
- * },
86
- * );
87
- * ```
88
17
  */
89
18
  const sessionCreate = mutation({
90
19
  args: {
@@ -147,16 +76,6 @@ const sessionIssue = mutation({
147
76
  * @param args.sessionId - The Convex document ID (`Id<"Session">`) of the session to retrieve.
148
77
  * @returns The session document if it exists, or `null` otherwise.
149
78
  *
150
- * @example
151
- * ```ts
152
- * const session = await ctx.runQuery(
153
- * component.identity.sessions.sessionGetById,
154
- * { sessionId: refreshToken.sessionId },
155
- * );
156
- * if (session !== null && session.expirationTime > Date.now()) {
157
- * console.log("Session is still active");
158
- * }
159
- * ```
160
79
  */
161
80
  const sessionGetById = query({
162
81
  args: { sessionId: v.id("Session") },
@@ -176,18 +95,6 @@ const sessionGetById = query({
176
95
  * @param args.sessionId - The document ID of the session to delete.
177
96
  * @returns `null` on success (including when the session was already absent).
178
97
  *
179
- * @example
180
- * ```ts
181
- * // Revoke a session and its tokens
182
- * await ctx.runMutation(
183
- * component.identity.sessions.sessionDelete,
184
- * { sessionId: session._id },
185
- * );
186
- * await ctx.runMutation(
187
- * component.identity.tokens.refreshTokenDeleteAll,
188
- * { sessionId: session._id },
189
- * );
190
- * ```
191
98
  */
192
99
  const sessionDelete = mutation({
193
100
  args: { sessionId: v.id("Session") },
@@ -200,23 +107,14 @@ const sessionDelete = mutation({
200
107
  /**
201
108
  * List all sessions belonging to a specific user.
202
109
  *
203
- * Queries the `Session` table using the `user_id` index to efficiently retrieve
204
- * every session document for the given user. Unlike `sessionList`, this returns
205
- * all matching sessions without pagination.
110
+ * Queries the `Session` table using the `user_id` index to retrieve
111
+ * every session document for the given user, as a flat array.
206
112
  *
207
113
  * @param args.userId - The document ID of the user whose sessions should be retrieved.
208
114
  * @returns An array of session documents for the specified user.
209
115
  *
210
- * @example
211
- * ```ts
212
- * const sessions = await ctx.runQuery(
213
- * component.identity.sessions.sessionListByUser,
214
- * { userId: user._id },
215
- * );
216
- * console.log(`User has ${sessions.length} active session(s)`);
217
- * ```
218
116
  */
219
- const sessionListByUser = query({
117
+ const sessionList = query({
220
118
  args: { userId: v.id("User") },
221
119
  returns: v.array(vSessionDoc),
222
120
  handler: async (ctx, { userId }) => {
@@ -225,5 +123,5 @@ const sessionListByUser = query({
225
123
  });
226
124
 
227
125
  //#endregion
228
- export { sessionCreate, sessionDelete, sessionGetById, sessionIssue, sessionList, sessionListByUser };
126
+ export { sessionCreate, sessionDelete, sessionGetById, sessionIssue, sessionList };
229
127
  //# sourceMappingURL=sessions.js.map
@@ -17,16 +17,6 @@ import { v } from "convex/values";
17
17
  * exchanged to create this one. Omitted for the initial token in a session.
18
18
  * @returns The document ID of the newly created refresh token.
19
19
  *
20
- * @example
21
- * ```ts
22
- * const tokenId = await ctx.runMutation(
23
- * component.identity.tokens.refreshTokenCreate,
24
- * {
25
- * sessionId: session._id,
26
- * expirationTime: Date.now() + 7 * 24 * 60 * 60 * 1000, // 7 days
27
- * },
28
- * );
29
- * ```
30
20
  */
31
21
  const refreshTokenCreate = mutation({
32
22
  args: {
@@ -40,30 +30,20 @@ const refreshTokenCreate = mutation({
40
30
  }
41
31
  });
42
32
  /**
43
- * Retrieve a single refresh token by its Convex document ID.
44
- *
45
- * Performs a direct point lookup on the `RefreshToken` table. Returns `null` if
46
- * the token has been deleted or never existed.
47
- *
48
- * @param args.refreshTokenId - The Convex document ID (`Id<"RefreshToken">`) of the token to retrieve.
49
- * @returns The refresh token document if it exists, or `null` otherwise.
50
- *
51
- * @example
52
- * ```ts
53
- * const token = await ctx.runQuery(
54
- * component.identity.tokens.refreshTokenGetById,
55
- * { refreshTokenId: storedTokenId },
56
- * );
57
- * if (token !== null && token.expirationTime > Date.now()) {
58
- * console.log("Refresh token is still valid");
59
- * }
60
- * ```
33
+ * Read a refresh token by identity one function, all-optional args,
34
+ * unioned return: `{ id }` (point lookup) or `{ activeForSession }`
35
+ * (newest unused token for a session).
61
36
  */
62
- const refreshTokenGetById = query({
63
- args: { refreshTokenId: v.id("RefreshToken") },
37
+ const refreshTokenGet = query({
38
+ args: {
39
+ id: v.optional(v.id("RefreshToken")),
40
+ activeForSession: v.optional(v.id("Session"))
41
+ },
64
42
  returns: v.union(vRefreshTokenDoc, v.null()),
65
- handler: async (ctx, { refreshTokenId }) => {
66
- return await ctx.db.get("RefreshToken", refreshTokenId);
43
+ handler: async (ctx, args) => {
44
+ if (args.activeForSession !== void 0) return await ctx.db.query("RefreshToken").withIndex("session_id_first_used", (q) => q.eq("sessionId", args.activeForSession).eq("firstUsedTime", void 0)).order("desc").first();
45
+ if (args.id === void 0) return null;
46
+ return await ctx.db.get("RefreshToken", args.id);
67
47
  }
68
48
  });
69
49
  /**
@@ -77,17 +57,6 @@ const refreshTokenGetById = query({
77
57
  * @param args.data - A partial object containing the fields to merge (e.g. `{ firstUsedTime: number }`).
78
58
  * @returns `null` on success.
79
59
  *
80
- * @example
81
- * ```ts
82
- * // Mark the refresh token as used
83
- * await ctx.runMutation(
84
- * component.identity.tokens.refreshTokenPatch,
85
- * {
86
- * refreshTokenId: token._id,
87
- * data: { firstUsedTime: Date.now() },
88
- * },
89
- * );
90
- * ```
91
60
  */
92
61
  const refreshTokenPatch = mutation({
93
62
  args: {
@@ -112,19 +81,6 @@ const refreshTokenPatch = mutation({
112
81
  * @param args.parentRefreshTokenId - The document ID of the parent refresh token whose children to retrieve.
113
82
  * @returns An array of refresh token documents that were derived from the specified parent token.
114
83
  *
115
- * @example
116
- * ```ts
117
- * const children = await ctx.runQuery(
118
- * component.identity.tokens.refreshTokenGetChildren,
119
- * {
120
- * sessionId: session._id,
121
- * parentRefreshTokenId: parentToken._id,
122
- * },
123
- * );
124
- * if (children.length > 1) {
125
- * console.warn("Possible token reuse detected!");
126
- * }
127
- * ```
128
84
  */
129
85
  const refreshTokenGetChildren = query({
130
86
  args: {
@@ -146,14 +102,6 @@ const refreshTokenGetChildren = query({
146
102
  * @param args.sessionId - The document ID of the session whose refresh tokens should be retrieved.
147
103
  * @returns An array of all refresh token documents for the specified session.
148
104
  *
149
- * @example
150
- * ```ts
151
- * const tokens = await ctx.runQuery(
152
- * component.identity.tokens.refreshTokenListBySession,
153
- * { sessionId: session._id },
154
- * );
155
- * console.log(`Session has ${tokens.length} refresh token(s)`);
156
- * ```
157
105
  */
158
106
  const refreshTokenListBySession = query({
159
107
  args: { sessionId: v.id("Session") },
@@ -173,14 +121,6 @@ const refreshTokenListBySession = query({
173
121
  * @param args.sessionId - The document ID of the session whose refresh tokens should be deleted.
174
122
  * @returns `null` on success.
175
123
  *
176
- * @example
177
- * ```ts
178
- * // Invalidate all tokens for a compromised session
179
- * await ctx.runMutation(
180
- * component.identity.tokens.refreshTokenDeleteAll,
181
- * { sessionId: session._id },
182
- * );
183
- * ```
184
124
  */
185
125
  const refreshTokenDeleteAll = mutation({
186
126
  args: { sessionId: v.id("Session") },
@@ -270,37 +210,7 @@ const refreshTokenExchange = mutation({
270
210
  return null;
271
211
  }
272
212
  });
273
- /**
274
- * Get the active (unused) refresh token for a session.
275
- *
276
- * Queries the `RefreshToken` table using the `session_id_first_used` index to
277
- * find the most recently created token for the session that has not yet been
278
- * exchanged (i.e. `firstUsedTime` is `undefined`). This represents the current
279
- * valid refresh token the client should be holding.
280
- *
281
- * @param args.sessionId - The document ID of the session whose active refresh token should be retrieved.
282
- * @returns The most recent unused refresh token document, or `null` if no active token exists
283
- * (e.g. all tokens have been consumed or the session has no tokens).
284
- *
285
- * @example
286
- * ```ts
287
- * const activeToken = await ctx.runQuery(
288
- * component.identity.tokens.refreshTokenGetActive,
289
- * { sessionId: session._id },
290
- * );
291
- * if (activeToken !== null) {
292
- * console.log(`Active token expires at: ${activeToken.expirationTime}`);
293
- * }
294
- * ```
295
- */
296
- const refreshTokenGetActive = query({
297
- args: { sessionId: v.id("Session") },
298
- returns: v.union(vRefreshTokenDoc, v.null()),
299
- handler: async (ctx, { sessionId }) => {
300
- return await ctx.db.query("RefreshToken").withIndex("session_id_first_used", (q) => q.eq("sessionId", sessionId).eq("firstUsedTime", void 0)).order("desc").first();
301
- }
302
- });
303
213
 
304
214
  //#endregion
305
- export { refreshTokenCreate, refreshTokenDeleteAll, refreshTokenExchange, refreshTokenGetActive, refreshTokenGetById, refreshTokenGetChildren, refreshTokenListBySession, refreshTokenPatch };
215
+ export { refreshTokenCreate, refreshTokenDeleteAll, refreshTokenExchange, refreshTokenGet, refreshTokenGetChildren, refreshTokenListBySession, refreshTokenPatch };
306
216
  //# sourceMappingURL=tokens.js.map