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

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.
@@ -1,9 +1,10 @@
1
1
  import { AuthAuthorizationConfig, ConvexAuthConfig, Doc, KeyDoc, KeyScope, ScopeChecker, UserOrderBy, UserWhere } from "../server/types.js";
2
2
  import { AuthConfig, AuthContext, AuthContextConfig, AuthContextFactory, AuthContextResolver, OptionalAuthContext, UserDoc } from "../server/facade.js";
3
3
  import { ComponentCtx, ComponentReadCtx } from "../server/component/context.js";
4
+ import "../server/identity/convex.js";
4
5
  import { AuthProfile } from "../server/payloads.js";
6
+ import "../server/index.js";
5
7
  import "../component/index.js";
6
- import "../server/identity/convex.js";
7
8
  import * as convex_values0 from "convex/values";
8
9
  import * as convex_server0 from "convex/server";
9
10
  import * as fluent_convex0 from "fluent-convex";
package/dist/model.js ADDED
@@ -0,0 +1,373 @@
1
+ import { v } from "convex/values";
2
+
3
+ //#region src/component/model.ts
4
+ const TABLES = {
5
+ User: "User",
6
+ Session: "Session",
7
+ Account: "Account",
8
+ AuthVerifier: "AuthVerifier",
9
+ VerificationCode: "VerificationCode",
10
+ RefreshToken: "RefreshToken",
11
+ Passkey: "Passkey",
12
+ TotpFactor: "TotpFactor",
13
+ RateLimit: "RateLimit",
14
+ Group: "Group",
15
+ GroupTag: "GroupTag",
16
+ GroupMember: "GroupMember",
17
+ GroupInvite: "GroupInvite",
18
+ GroupConnection: "GroupConnection",
19
+ GroupConnectionDomain: "GroupConnectionDomain",
20
+ GroupConnectionDomainVerification: "GroupConnectionDomainVerification",
21
+ GroupConnectionSecret: "GroupConnectionSecret",
22
+ GroupConnectionScimConfig: "GroupConnectionScimConfig",
23
+ GroupConnectionScimIdentity: "GroupConnectionScimIdentity",
24
+ GroupAuditEvent: "GroupAuditEvent",
25
+ GroupWebhookEndpoint: "GroupWebhookEndpoint",
26
+ GroupWebhookDelivery: "GroupWebhookDelivery",
27
+ ApiKey: "ApiKey",
28
+ DeviceCode: "DeviceCode"
29
+ };
30
+ const vTag = v.object({
31
+ key: v.string(),
32
+ value: v.string()
33
+ });
34
+ const vPaginated = (item) => v.object({
35
+ items: v.array(item),
36
+ nextCursor: v.union(v.string(), v.null())
37
+ });
38
+ const vInviteStatus = v.union(v.literal("pending"), v.literal("accepted"), v.literal("revoked"), v.literal("expired"));
39
+ const vDeviceStatus = v.union(v.literal("pending"), v.literal("authorized"), v.literal("denied"));
40
+ const vGroupConnectionAccountLinkingPolicy = v.union(v.literal("verifiedEmail"), v.literal("none"));
41
+ const vGroupConnectionScimReuseUserPolicy = v.union(v.literal("externalId"), v.literal("none"));
42
+ const vGroupConnectionJitProvisioningMode = v.union(v.literal("off"), v.literal("createUser"), v.literal("createUserAndMembership"));
43
+ const vGroupConnectionDeprovisionMode = v.union(v.literal("soft"), v.literal("hard"));
44
+ const vGroupConnectionProfileUpdateMode = v.union(v.literal("never"), v.literal("missing"), v.literal("always"));
45
+ const vGroupConnectionProvisioningAuthority = v.union(v.literal("app"), v.literal("sso"), v.literal("scim"));
46
+ const vGroupConnectionGroupSyncMode = v.union(v.literal("ignore"), v.literal("sync"));
47
+ const vGroupConnectionRoleSyncMode = v.union(v.literal("ignore"), v.literal("map"));
48
+ const vGroupConnectionStatus = v.union(v.literal("draft"), v.literal("active"), v.literal("disabled"));
49
+ const vGroupConnectionProtocol = v.union(v.literal("oidc"), v.literal("saml"));
50
+ const vGroupConnectionPolicy = v.object({
51
+ version: v.literal(1),
52
+ identity: v.object({ accountLinking: v.object({
53
+ oidc: vGroupConnectionAccountLinkingPolicy,
54
+ saml: vGroupConnectionAccountLinkingPolicy
55
+ }) }),
56
+ provisioning: v.object({
57
+ user: v.object({
58
+ createOnSignIn: v.boolean(),
59
+ updateProfileOnLogin: vGroupConnectionProfileUpdateMode,
60
+ updateProfileFromScim: vGroupConnectionProfileUpdateMode,
61
+ authority: vGroupConnectionProvisioningAuthority
62
+ }),
63
+ scimReuse: v.object({ user: vGroupConnectionScimReuseUserPolicy }),
64
+ jit: v.object({
65
+ mode: vGroupConnectionJitProvisioningMode,
66
+ defaultRole: v.optional(v.string()),
67
+ defaultRoleIds: v.optional(v.array(v.string()))
68
+ }),
69
+ deprovision: v.object({ mode: vGroupConnectionDeprovisionMode }),
70
+ groups: v.object({
71
+ mode: vGroupConnectionGroupSyncMode,
72
+ source: v.literal("protocol"),
73
+ mapping: v.optional(v.record(v.string(), v.array(v.string())))
74
+ }),
75
+ roles: v.object({
76
+ mode: vGroupConnectionRoleSyncMode,
77
+ source: v.literal("protocol"),
78
+ mapping: v.optional(v.record(v.string(), v.array(v.string())))
79
+ })
80
+ }),
81
+ extend: v.optional(v.any())
82
+ });
83
+ const vScimStatus = v.union(v.literal("draft"), v.literal("active"), v.literal("disabled"));
84
+ const vScimResourceType = v.union(v.literal("user"), v.literal("group"));
85
+ const vAuditActorType = v.union(v.literal("user"), v.literal("system"), v.literal("scim"), v.literal("api_key"), v.literal("webhook"));
86
+ const vAuditStatus = v.union(v.literal("success"), v.literal("failure"));
87
+ const vWebhookEndpointStatus = v.union(v.literal("active"), v.literal("disabled"));
88
+ const vWebhookDeliveryStatus = v.union(v.literal("pending"), v.literal("processing"), v.literal("delivered"), v.literal("failed"));
89
+ const vInviteTokenAcceptStatus = v.union(v.literal("accepted"), v.literal("already_accepted"));
90
+ const vMembershipStatus = v.union(v.literal("joined"), v.literal("already_joined"), v.literal("not_applicable"));
91
+ const vApiKeyScope = v.object({
92
+ resource: v.string(),
93
+ actions: v.array(v.string())
94
+ });
95
+ const vApiKeyRateLimit = v.object({
96
+ maxRequests: v.number(),
97
+ windowMs: v.number()
98
+ });
99
+ const vApiKeyRateLimitState = v.object({
100
+ attemptsLeft: v.number(),
101
+ lastAttemptTime: v.number()
102
+ });
103
+ const vGroupConnectionSecretKind = v.union(v.literal("oidc_client_secret"));
104
+ function vDocMeta(tableName) {
105
+ return {
106
+ _id: v.id(tableName),
107
+ _creationTime: v.number()
108
+ };
109
+ }
110
+ const vUserDoc = v.object({
111
+ ...vDocMeta(TABLES.User),
112
+ name: v.optional(v.string()),
113
+ image: v.optional(v.string()),
114
+ email: v.optional(v.string()),
115
+ emailVerificationTime: v.optional(v.number()),
116
+ phone: v.optional(v.string()),
117
+ phoneVerificationTime: v.optional(v.number()),
118
+ isAnonymous: v.optional(v.boolean()),
119
+ hasTotp: v.optional(v.boolean()),
120
+ extend: v.optional(v.any())
121
+ });
122
+ const vSessionDoc = v.object({
123
+ ...vDocMeta(TABLES.Session),
124
+ userId: v.id(TABLES.User),
125
+ expirationTime: v.number()
126
+ });
127
+ const vAccountDoc = v.object({
128
+ ...vDocMeta(TABLES.Account),
129
+ userId: v.id(TABLES.User),
130
+ provider: v.string(),
131
+ providerAccountId: v.string(),
132
+ secret: v.optional(v.string()),
133
+ emailVerified: v.optional(v.string()),
134
+ phoneVerified: v.optional(v.string()),
135
+ extend: v.optional(v.any())
136
+ });
137
+ const vAuthVerifierDoc = v.object({
138
+ ...vDocMeta(TABLES.AuthVerifier),
139
+ sessionId: v.optional(v.id(TABLES.Session)),
140
+ signature: v.optional(v.string()),
141
+ expirationTime: v.optional(v.number())
142
+ });
143
+ const vVerificationCodeDoc = v.object({
144
+ ...vDocMeta(TABLES.VerificationCode),
145
+ accountId: v.id(TABLES.Account),
146
+ provider: v.string(),
147
+ code: v.string(),
148
+ expirationTime: v.number(),
149
+ verifier: v.optional(v.string()),
150
+ emailVerified: v.optional(v.string()),
151
+ phoneVerified: v.optional(v.string())
152
+ });
153
+ const vRefreshTokenDoc = v.object({
154
+ ...vDocMeta(TABLES.RefreshToken),
155
+ sessionId: v.id(TABLES.Session),
156
+ expirationTime: v.number(),
157
+ firstUsedTime: v.optional(v.number()),
158
+ parentRefreshTokenId: v.optional(v.id(TABLES.RefreshToken))
159
+ });
160
+ const vPasskeyDoc = v.object({
161
+ ...vDocMeta(TABLES.Passkey),
162
+ userId: v.id(TABLES.User),
163
+ credentialId: v.string(),
164
+ publicKey: v.bytes(),
165
+ algorithm: v.number(),
166
+ counter: v.number(),
167
+ transports: v.optional(v.array(v.string())),
168
+ deviceType: v.string(),
169
+ backedUp: v.boolean(),
170
+ name: v.optional(v.string()),
171
+ createdAt: v.number(),
172
+ lastUsedAt: v.optional(v.number())
173
+ });
174
+ const vTotpFactorDoc = v.object({
175
+ ...vDocMeta(TABLES.TotpFactor),
176
+ userId: v.id(TABLES.User),
177
+ secret: v.bytes(),
178
+ digits: v.number(),
179
+ period: v.number(),
180
+ verified: v.boolean(),
181
+ name: v.optional(v.string()),
182
+ createdAt: v.number(),
183
+ lastUsedAt: v.optional(v.number())
184
+ });
185
+ const vRateLimitDoc = v.object({
186
+ ...vDocMeta(TABLES.RateLimit),
187
+ identifier: v.string(),
188
+ last_attempt_time: v.number(),
189
+ attempts_left: v.number()
190
+ });
191
+ const vGroupDoc = v.object({
192
+ ...vDocMeta(TABLES.Group),
193
+ name: v.string(),
194
+ slug: v.optional(v.string()),
195
+ type: v.optional(v.string()),
196
+ parentGroupId: v.optional(v.id(TABLES.Group)),
197
+ rootGroupId: v.optional(v.id(TABLES.Group)),
198
+ isRoot: v.optional(v.boolean()),
199
+ tags: v.optional(v.array(vTag)),
200
+ policy: v.optional(vGroupConnectionPolicy),
201
+ extend: v.optional(v.any())
202
+ });
203
+ const vGroupMemberDoc = v.object({
204
+ ...vDocMeta(TABLES.GroupMember),
205
+ groupId: v.id(TABLES.Group),
206
+ userId: v.id(TABLES.User),
207
+ role: v.optional(v.string()),
208
+ roleIds: v.optional(v.array(v.string())),
209
+ status: v.optional(v.string()),
210
+ extend: v.optional(v.any())
211
+ });
212
+ const vGroupInviteDoc = v.object({
213
+ ...vDocMeta(TABLES.GroupInvite),
214
+ groupId: v.optional(v.id(TABLES.Group)),
215
+ invitedByUserId: v.optional(v.id(TABLES.User)),
216
+ email: v.optional(v.string()),
217
+ tokenHash: v.string(),
218
+ role: v.optional(v.string()),
219
+ roleIds: v.optional(v.array(v.string())),
220
+ status: vInviteStatus,
221
+ expiresTime: v.optional(v.number()),
222
+ acceptedByUserId: v.optional(v.id(TABLES.User)),
223
+ acceptedTime: v.optional(v.number()),
224
+ extend: v.optional(v.any())
225
+ });
226
+ const vApiKeyDoc = v.object({
227
+ ...vDocMeta(TABLES.ApiKey),
228
+ userId: v.id(TABLES.User),
229
+ prefix: v.string(),
230
+ hashedKey: v.string(),
231
+ name: v.string(),
232
+ scopes: v.array(vApiKeyScope),
233
+ rateLimit: v.optional(vApiKeyRateLimit),
234
+ rateLimitState: v.optional(vApiKeyRateLimitState),
235
+ expiresAt: v.optional(v.number()),
236
+ lastUsedAt: v.optional(v.number()),
237
+ createdAt: v.number(),
238
+ revoked: v.boolean(),
239
+ metadata: v.optional(v.any())
240
+ });
241
+ const vDeviceCodeDoc = v.object({
242
+ ...vDocMeta(TABLES.DeviceCode),
243
+ deviceCodeHash: v.string(),
244
+ userCode: v.string(),
245
+ expiresAt: v.number(),
246
+ interval: v.number(),
247
+ status: vDeviceStatus,
248
+ userId: v.optional(v.id(TABLES.User)),
249
+ sessionId: v.optional(v.id(TABLES.Session)),
250
+ lastPolledAt: v.optional(v.number())
251
+ });
252
+ const vGroupConnectionDoc = v.object({
253
+ ...vDocMeta(TABLES.GroupConnection),
254
+ groupId: v.id(TABLES.Group),
255
+ slug: v.optional(v.string()),
256
+ name: v.optional(v.string()),
257
+ protocol: vGroupConnectionProtocol,
258
+ status: vGroupConnectionStatus,
259
+ config: v.optional(v.any()),
260
+ extend: v.optional(v.any())
261
+ });
262
+ const vGroupConnectionDomainDoc = v.object({
263
+ ...vDocMeta(TABLES.GroupConnectionDomain),
264
+ connectionId: v.id(TABLES.GroupConnection),
265
+ groupId: v.id(TABLES.Group),
266
+ domain: v.string(),
267
+ isPrimary: v.boolean(),
268
+ verifiedAt: v.optional(v.number())
269
+ });
270
+ const vGroupConnectionDomainVerificationDoc = v.object({
271
+ ...vDocMeta(TABLES.GroupConnectionDomainVerification),
272
+ connectionId: v.id(TABLES.GroupConnection),
273
+ groupId: v.id(TABLES.Group),
274
+ domainId: v.id(TABLES.GroupConnectionDomain),
275
+ domain: v.string(),
276
+ recordName: v.string(),
277
+ token: v.string(),
278
+ tokenHash: v.string(),
279
+ requestedAt: v.number(),
280
+ expiresAt: v.number()
281
+ });
282
+ const vGroupConnectionSecretDoc = v.object({
283
+ ...vDocMeta(TABLES.GroupConnectionSecret),
284
+ connectionId: v.id(TABLES.GroupConnection),
285
+ groupId: v.id(TABLES.Group),
286
+ kind: vGroupConnectionSecretKind,
287
+ ciphertext: v.string(),
288
+ updatedAt: v.number()
289
+ });
290
+ const vGroupConnectionScimConfigDoc = v.object({
291
+ ...vDocMeta(TABLES.GroupConnectionScimConfig),
292
+ connectionId: v.id(TABLES.GroupConnection),
293
+ groupId: v.id(TABLES.Group),
294
+ status: vScimStatus,
295
+ basePath: v.string(),
296
+ tokenHash: v.string(),
297
+ lastRotatedAt: v.optional(v.number()),
298
+ extend: v.optional(v.any())
299
+ });
300
+ const vGroupConnectionScimIdentityDoc = v.object({
301
+ ...vDocMeta(TABLES.GroupConnectionScimIdentity),
302
+ connectionId: v.id(TABLES.GroupConnection),
303
+ groupId: v.id(TABLES.Group),
304
+ resourceType: vScimResourceType,
305
+ externalId: v.string(),
306
+ userId: v.optional(v.id(TABLES.User)),
307
+ mappedGroupId: v.optional(v.id(TABLES.Group)),
308
+ lastProvisionedAt: v.optional(v.number()),
309
+ active: v.optional(v.boolean()),
310
+ raw: v.optional(v.any())
311
+ });
312
+ const vGroupAuditEventDoc = v.object({
313
+ ...vDocMeta(TABLES.GroupAuditEvent),
314
+ connectionId: v.optional(v.id(TABLES.GroupConnection)),
315
+ groupId: v.id(TABLES.Group),
316
+ eventType: v.string(),
317
+ actorType: vAuditActorType,
318
+ actorId: v.optional(v.string()),
319
+ subjectType: v.string(),
320
+ subjectId: v.optional(v.string()),
321
+ status: vAuditStatus,
322
+ occurredAt: v.number(),
323
+ requestId: v.optional(v.string()),
324
+ ip: v.optional(v.string()),
325
+ metadata: v.optional(v.any())
326
+ });
327
+ const vGroupWebhookEndpointDoc = v.object({
328
+ ...vDocMeta(TABLES.GroupWebhookEndpoint),
329
+ connectionId: v.id(TABLES.GroupConnection),
330
+ groupId: v.id(TABLES.Group),
331
+ url: v.string(),
332
+ status: vWebhookEndpointStatus,
333
+ secretHash: v.string(),
334
+ subscriptions: v.array(v.string()),
335
+ createdByUserId: v.optional(v.id(TABLES.User)),
336
+ lastSuccessAt: v.optional(v.number()),
337
+ lastFailureAt: v.optional(v.number()),
338
+ failureCount: v.number(),
339
+ extend: v.optional(v.any())
340
+ });
341
+ const vGroupWebhookDeliveryDoc = v.object({
342
+ ...vDocMeta(TABLES.GroupWebhookDelivery),
343
+ connectionId: v.id(TABLES.GroupConnection),
344
+ endpointId: v.id(TABLES.GroupWebhookEndpoint),
345
+ auditEventId: v.optional(v.id(TABLES.GroupAuditEvent)),
346
+ eventType: v.string(),
347
+ status: vWebhookDeliveryStatus,
348
+ attemptCount: v.number(),
349
+ nextAttemptAt: v.number(),
350
+ lastAttemptAt: v.optional(v.number()),
351
+ lastResponseStatus: v.optional(v.number()),
352
+ lastError: v.optional(v.string()),
353
+ payload: v.any()
354
+ });
355
+ const vRateLimitResult = v.object({
356
+ ...vDocMeta(TABLES.RateLimit),
357
+ identifier: v.string(),
358
+ last_attempt_time: v.number(),
359
+ attempts_left: v.number(),
360
+ attemptsLeft: v.number(),
361
+ lastAttemptTime: v.number()
362
+ });
363
+ const vInviteAcceptByTokenResult = v.object({
364
+ inviteId: v.id(TABLES.GroupInvite),
365
+ groupId: v.union(v.id(TABLES.Group), v.null()),
366
+ memberId: v.optional(v.id(TABLES.GroupMember)),
367
+ inviteStatus: vInviteTokenAcceptStatus,
368
+ membershipStatus: vMembershipStatus
369
+ });
370
+
371
+ //#endregion
372
+ export { vGroupDoc, vGroupInviteDoc, vGroupMemberDoc, vPaginated, vUserDoc };
373
+ //# sourceMappingURL=model.js.map
@@ -3,6 +3,7 @@ import "../client/index.js";
3
3
  import { AuthAuthorizationConfig, AuthGrant, AuthProviderConfig, AuthRoleId, ConvexAuthConfig, HasDeviceProvider, HasPasskeyProvider, HasSSO, HasTotpProvider } from "./types.js";
4
4
  import { AuthConfig, AuthContext, AuthContextConfig, AuthContextFactory, AuthContextResolver, InferAuth, OptionalAuthContext, UserDoc } from "./facade.js";
5
5
  import { Auth } from "./runtime.js";
6
+ import { AuthExtendValidators, AuthValidators } from "./validators.js";
6
7
 
7
8
  //#region src/server/auth.d.ts
8
9
  type MemberApiWithAuthorization<TAuthorization extends AuthAuthorizationConfig | undefined> = Omit<ReturnType<typeof Auth>["auth"]["member"], "create" | "list" | "update" | "inspect" | "require"> & {
@@ -57,7 +58,57 @@ type MemberApiWithAuthorization<TAuthorization extends AuthAuthorizationConfig |
57
58
  * @typeParam TAuthorization - The authorization config, used to narrow
58
59
  * role IDs and grant strings on the `member` API.
59
60
  */
60
- type AuthApiBase<TAuthorization extends AuthAuthorizationConfig | undefined = undefined> = {
61
+ type AuthApiBase<TAuthorization extends AuthAuthorizationConfig | undefined = undefined, TExtend extends AuthExtendValidators = {}> = {
62
+ /**
63
+ * Convex `returns:` validators for the auth read surface.
64
+ *
65
+ * Set these as a function's `returns:` so client-side `useQuery`
66
+ * inference flows end-to-end without hand-rolled validators or DTO
67
+ * mappers. The `extend` field of each document carries the shape
68
+ * supplied via `createAuth({ extend: { ... } })`.
69
+ *
70
+ * Available validators:
71
+ * - `v.user` / `v.group` / `v.member` — single documents (extend-aware).
72
+ * - `v.invite` — a single group invite document.
73
+ * - `v.viewer` — `User | null`, for a current-user query.
74
+ * - `v.list(item)` — wraps an item validator in `{ items, nextCursor }`.
75
+ *
76
+ * Compose these for richer reads — e.g. a current user plus their
77
+ * memberships and groups — using the existing `auth.user.viewer`,
78
+ * `auth.member.list`, and `auth.group.get` facade methods.
79
+ *
80
+ * @example
81
+ * ```ts
82
+ * export const viewer = authQuery({
83
+ * returns: auth.v.viewer,
84
+ * handler: (ctx) => ctx.auth.user.viewer(ctx),
85
+ * });
86
+ *
87
+ * export const groups = authQuery({
88
+ * returns: v.union(
89
+ * v.object({
90
+ * ...auth.v.user.fields,
91
+ * memberships: v.array(auth.v.member),
92
+ * groups: v.array(auth.v.group),
93
+ * }),
94
+ * v.null(),
95
+ * ),
96
+ * handler: async (ctx) => {
97
+ * const me = await ctx.auth.user.viewer(ctx);
98
+ * if (me === null) return null;
99
+ * const { items: memberships } = await ctx.auth.member.list(ctx, {
100
+ * where: { userId: me._id },
101
+ * });
102
+ * const groups = await ctx.auth.group.get(
103
+ * ctx,
104
+ * memberships.map((m) => m.groupId),
105
+ * );
106
+ * return { ...me, memberships, groups };
107
+ * },
108
+ * });
109
+ * ```
110
+ */
111
+ v: AuthValidators<TExtend>;
61
112
  signIn: ReturnType<typeof Auth>["signIn"];
62
113
  signOut: ReturnType<typeof Auth>["signOut"];
63
114
  store: ReturnType<typeof Auth>["store"];
@@ -244,8 +295,8 @@ type PublicGroupSsoApi = {
244
295
  * @typeParam TAuthorization - The authorization config, forwarded to
245
296
  * {@link AuthApiBase} for typed role IDs and grant strings.
246
297
  */
247
- type AuthApi<TAuthorization extends AuthAuthorizationConfig | undefined = undefined> = AuthApiBase<TAuthorization> & {
248
- group: AuthApiBase<TAuthorization>["group"] & {
298
+ type AuthApi<TAuthorization extends AuthAuthorizationConfig | undefined = undefined, TExtend extends AuthExtendValidators = {}> = AuthApiBase<TAuthorization, TExtend> & {
299
+ group: AuthApiBase<TAuthorization, TExtend>["group"] & {
249
300
  sso: PublicGroupSsoApi;
250
301
  };
251
302
  };
@@ -264,7 +315,7 @@ type AuthApi<TAuthorization extends AuthAuthorizationConfig | undefined = undefi
264
315
  * @typeParam P - The tuple of provider configs passed to `createAuth`.
265
316
  * @typeParam TAuthorization - Optional authorization config for typed roles/grants.
266
317
  */
267
- type ConvexAuthResult<P extends AuthProviderConfig[], TAuthorization extends AuthAuthorizationConfig | undefined = undefined> = HasSSO<P> extends true ? AuthApi<TAuthorization> : AuthApiBase<TAuthorization>;
318
+ type ConvexAuthResult<P extends AuthProviderConfig[], TAuthorization extends AuthAuthorizationConfig | undefined = undefined, TExtend extends AuthExtendValidators = {}> = HasSSO<P> extends true ? AuthApi<TAuthorization, TExtend> : AuthApiBase<TAuthorization, TExtend>;
268
319
  /**
269
320
  * Infer the typed `AuthApiRefs` for the client SDK from a `createAuth` call.
270
321
  *
@@ -309,10 +360,24 @@ type InferClientApi<T> = T extends ConvexAuthResult<infer P> ? AuthApiRefs<HasPa
309
360
  *
310
361
  * @see {@link AuthContextConfig}
311
362
  */
312
- declare function createAuth<P extends AuthProviderConfig[], TAuthorization extends AuthAuthorizationConfig | undefined = undefined>(component: ConvexAuthConfig["component"], config: Omit<AuthConfig, "providers" | "authorization"> & {
363
+ declare function createAuth<P extends AuthProviderConfig[], TAuthorization extends AuthAuthorizationConfig | undefined = undefined, TExtend extends AuthExtendValidators = {}>(component: ConvexAuthConfig["component"], config: Omit<AuthConfig, "providers" | "authorization"> & {
313
364
  providers: P;
314
365
  authorization?: TAuthorization;
315
- }): ConvexAuthResult<P, TAuthorization>;
366
+ /**
367
+ * Validators for the `extend` field of each table. Drives both the
368
+ * inferred type of `auth.v.*` (so `viewer.extend.<field>` is typed)
369
+ * and runtime validation of consumer return shapes.
370
+ *
371
+ * @example
372
+ * ```ts
373
+ * createAuth(components.auth, {
374
+ * providers: [password()],
375
+ * extend: { User: v.object({ lastActiveGroup: v.optional(v.string()) }) },
376
+ * });
377
+ * ```
378
+ */
379
+ extend?: TExtend;
380
+ }): ConvexAuthResult<P, TAuthorization, TExtend>;
316
381
  //#endregion
317
382
  export { AuthApi, AuthApiBase, ConvexAuthResult, InferClientApi, createAuth };
318
383
  //# sourceMappingURL=auth.d.ts.map
@@ -1,5 +1,6 @@
1
1
  import { createAuthContextFacade } from "./facade.js";
2
2
  import { Auth } from "./runtime.js";
3
+ import { buildAuthValidators } from "./validators.js";
3
4
  import { ConvexError } from "convex/values";
4
5
 
5
6
  //#region src/server/auth.ts
@@ -130,6 +131,7 @@ function createAuth(component, config) {
130
131
  }
131
132
  };
132
133
  return {
134
+ v: buildAuthValidators(config.extend ?? {}),
133
135
  signIn: authResult.signIn,
134
136
  signOut: authResult.signOut,
135
137
  store: authResult.store,
@@ -1,9 +1,11 @@
1
- import { AfterCtx, AuthCallbackContext, AuthCallbackProfile, AuthCallbacks, AuthEvent, BeforeCtx, BeforeEvent, BeforeResult } from "./types.js";
1
+ import { vGroupDoc, vGroupInviteDoc, vGroupMemberDoc, vPaginated, vUserDoc } from "../component/model.js";
2
+ import { AfterCtx, AuthCallbackContext, AuthCallbackProfile, AuthCallbacks, AuthDataModel, AuthEvent, BeforeCtx, BeforeEvent, BeforeResult, Doc, GenericDoc } from "./types.js";
2
3
  import { AuthConfig, AuthContext, AuthContextConfig, InferAuth, OptionalAuthContext, UserDoc } from "./facade.js";
4
+ import "./identity/convex.js";
3
5
  import { WellKnownEndpoint, WellKnownOptions, WellKnownResponse, wellKnown } from "./wellknown.js";
4
6
  import { HttpAuthContext, HttpAuthContextConfig, OptionalHttpAuthContext } from "./http.js";
7
+ import { AuthExtendValidators, AuthValidators, Group, Membership, Viewer, buildAuthValidators } from "./validators.js";
5
8
  import { AuthApi, AuthApiBase, ConvexAuthResult, InferClientApi, createAuth } from "./auth.js";
6
- import "./identity/convex.js";
7
9
  import { CreateAuthGroupSsoOptions, GroupSsoAccessHandler, GroupSsoAccessInput, GroupSsoAccessPermissions, GroupSsoPermission, GroupSsoResolvedAccessHandler, createAuthGroupSso, scim, sso } from "./mounts.js";
8
10
  import { AuthCookie, AuthCookieConfig, AuthCookies, RefreshResult, ServerOptions, authCookieNames, parseAuthCookies, serializeAuthCookies, server, shouldProxyAuthAction, structuredAuthCookies } from "./prefetch.js";
9
- export { type AfterCtx, type AuthApi, type AuthApiBase, type AuthCallbackContext, type AuthCallbackProfile, type AuthCallbacks, type AuthConfig, type AuthContext, type AuthContextConfig, type AuthCookie, type AuthCookieConfig, type AuthCookies, type AuthEvent, type BeforeCtx, type BeforeEvent, type BeforeResult, type ConvexAuthResult, type CreateAuthGroupSsoOptions, type GroupSsoAccessHandler, type GroupSsoAccessInput, type GroupSsoAccessPermissions, type GroupSsoPermission, type GroupSsoResolvedAccessHandler, type HttpAuthContext, type HttpAuthContextConfig, type InferAuth, type InferClientApi, type OptionalAuthContext, type OptionalHttpAuthContext, type RefreshResult, type ServerOptions, type UserDoc, type WellKnownEndpoint, type WellKnownOptions, type WellKnownResponse, authCookieNames, createAuth, createAuthGroupSso, parseAuthCookies, scim, serializeAuthCookies, server, shouldProxyAuthAction, sso, structuredAuthCookies, wellKnown };
11
+ export { type AfterCtx, type AuthApi, type AuthApiBase, type AuthCallbackContext, type AuthCallbackProfile, type AuthCallbacks, type AuthConfig, type AuthContext, type AuthContextConfig, type AuthCookie, type AuthCookieConfig, type AuthCookies, type AuthDataModel, type AuthEvent, type AuthExtendValidators, type AuthValidators, type BeforeCtx, type BeforeEvent, type BeforeResult, type ConvexAuthResult, type CreateAuthGroupSsoOptions, type Doc, type GenericDoc, type Group, type GroupSsoAccessHandler, type GroupSsoAccessInput, type GroupSsoAccessPermissions, type GroupSsoPermission, type GroupSsoResolvedAccessHandler, type HttpAuthContext, type HttpAuthContextConfig, type InferAuth, type InferClientApi, type Membership, type OptionalAuthContext, type OptionalHttpAuthContext, type RefreshResult, type ServerOptions, type UserDoc, type Viewer, type WellKnownEndpoint, type WellKnownOptions, type WellKnownResponse, authCookieNames, buildAuthValidators, createAuth, createAuthGroupSso, parseAuthCookies, scim, serializeAuthCookies, server, shouldProxyAuthAction, sso, structuredAuthCookies, vGroupDoc, vGroupInviteDoc, vGroupMemberDoc, vPaginated, vUserDoc, wellKnown };
@@ -1,7 +1,9 @@
1
1
  import "./identity/convex.js";
2
+ import { vGroupDoc, vGroupInviteDoc, vGroupMemberDoc, vPaginated, vUserDoc } from "../component/model.js";
2
3
  import { wellKnown } from "./wellknown.js";
4
+ import { buildAuthValidators } from "./validators.js";
3
5
  import { createAuth } from "./auth.js";
4
6
  import { createAuthGroupSso, scim, sso } from "./mounts.js";
5
7
  import { authCookieNames, parseAuthCookies, serializeAuthCookies, server, shouldProxyAuthAction, structuredAuthCookies } from "./prefetch.js";
6
8
 
7
- export { authCookieNames, createAuth, createAuthGroupSso, parseAuthCookies, scim, serializeAuthCookies, server, shouldProxyAuthAction, sso, structuredAuthCookies, wellKnown };
9
+ export { authCookieNames, buildAuthValidators, createAuth, createAuthGroupSso, parseAuthCookies, scim, serializeAuthCookies, server, shouldProxyAuthAction, sso, structuredAuthCookies, vGroupDoc, vGroupInviteDoc, vGroupMemberDoc, vPaginated, vUserDoc, wellKnown };