@robelest/convex-auth 0.0.4-preview.16 → 0.0.4-preview.18
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.
- package/dist/authorization/index.d.ts +17 -0
- package/dist/authorization/index.d.ts.map +1 -0
- package/dist/authorization/index.js +17 -0
- package/dist/authorization/index.js.map +1 -0
- package/dist/client/index.js +73 -0
- package/dist/client/index.js.map +1 -1
- package/dist/component/_generated/component.d.ts +52 -0
- package/dist/component/_generated/component.d.ts.map +1 -1
- package/dist/component/convex.config.d.ts +2 -2
- package/dist/component/convex.config.d.ts.map +1 -1
- package/dist/component/index.js +2 -2
- package/dist/component/model.d.ts +75 -75
- package/dist/component/model.d.ts.map +1 -1
- package/dist/component/model.js +2 -0
- package/dist/component/model.js.map +1 -1
- package/dist/component/public/factors.d.ts.map +1 -1
- package/dist/component/public/factors.js +1 -1
- package/dist/component/public/factors.js.map +1 -1
- package/dist/component/public/groups.d.ts +10 -2
- package/dist/component/public/groups.d.ts.map +1 -1
- package/dist/component/public/groups.js +92 -8
- package/dist/component/public/groups.js.map +1 -1
- package/dist/component/public/identity.d.ts.map +1 -1
- package/dist/component/public/identity.js +3 -3
- package/dist/component/public/identity.js.map +1 -1
- package/dist/component/public/shared.d.ts +4 -4
- package/dist/component/public/shared.d.ts.map +1 -1
- package/dist/component/public.d.ts +3 -3
- package/dist/component/public.js +2 -2
- package/dist/component/schema.d.ts +13 -2
- package/dist/component/schema.js +7 -5
- package/dist/component/schema.js.map +1 -1
- package/dist/component/server/auth.d.ts +4 -25
- package/dist/component/server/auth.d.ts.map +1 -1
- package/dist/component/server/auth.js +4 -10
- package/dist/component/server/auth.js.map +1 -1
- package/dist/component/server/domains/core.js +196 -131
- package/dist/component/server/domains/core.js.map +1 -1
- package/dist/component/server/factory.d.ts +3 -3
- package/dist/component/server/signin.js +20 -1
- package/dist/component/server/signin.js.map +1 -1
- package/dist/server/auth.d.ts +4 -25
- package/dist/server/auth.d.ts.map +1 -1
- package/dist/server/auth.js +4 -10
- package/dist/server/auth.js.map +1 -1
- package/dist/server/domains/core.d.ts +73 -58
- package/dist/server/domains/core.d.ts.map +1 -1
- package/dist/server/domains/core.js +196 -131
- package/dist/server/domains/core.js.map +1 -1
- package/dist/server/http.d.ts +2 -2
- package/dist/server/http.d.ts.map +1 -1
- package/dist/server/index.d.ts +108 -69
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +138 -54
- package/dist/server/index.js.map +1 -1
- package/dist/server/mutations/code.d.ts +9 -9
- package/dist/server/mutations/index.d.ts +69 -69
- package/dist/server/mutations/invalidate.d.ts +4 -4
- package/dist/server/mutations/invalidate.d.ts.map +1 -1
- package/dist/server/mutations/oauth.d.ts +7 -7
- package/dist/server/mutations/register.d.ts +9 -9
- package/dist/server/mutations/retrieve.d.ts +6 -6
- package/dist/server/mutations/retrieve.d.ts.map +1 -1
- package/dist/server/mutations/signature.d.ts +4 -4
- package/dist/server/mutations/signature.d.ts.map +1 -1
- package/dist/server/mutations/signin.d.ts +5 -5
- package/dist/server/mutations/signin.d.ts.map +1 -1
- package/dist/server/mutations/verify.d.ts +7 -7
- package/dist/server/signin.js +20 -1
- package/dist/server/signin.js.map +1 -1
- package/dist/server/version.d.ts +1 -1
- package/dist/server/version.js +1 -1
- package/dist/server/version.js.map +1 -1
- package/package.json +9 -5
- package/src/authorization/index.ts +37 -0
- package/src/client/index.ts +122 -0
- package/src/component/_generated/component.ts +64 -0
- package/src/component/index.ts +1 -1
- package/src/component/model.ts +2 -0
- package/src/component/public/factors.ts +3 -2
- package/src/component/public/groups.ts +142 -8
- package/src/component/public/identity.ts +9 -6
- package/src/component/schema.ts +14 -2
- package/src/server/auth.ts +9 -61
- package/src/server/domains/core.ts +235 -210
- package/src/server/index.ts +158 -75
- package/src/server/signin.ts +52 -0
- package/src/server/version.ts +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core.js","names":[],"sources":["../../../../src/server/domains/core.ts"],"sourcesContent":["import { Auth, GenericActionCtx, GenericDataModel } from \"convex/server\";\nimport { GenericId } from \"convex/values\";\n\nimport { AuthError, Fx } from \"../fx\";\nimport {\n buildScopeChecker,\n checkKeyRateLimit,\n generateApiKey,\n hashApiKey,\n} from \"../keys\";\nimport { materializeProvider } from \"../providers\";\nimport { signInImpl } from \"../signin\";\nimport type {\n AuthProviderConfig,\n KeyDoc,\n KeyScope,\n ScopeChecker,\n UserOrderBy,\n UserWhere,\n} from \"../types\";\nimport {\n generateRandomString,\n sha256,\n TOKEN_SUB_CLAIM_DIVIDER,\n} from \"../utils\";\n\ntype ComponentCtx = Pick<\n GenericActionCtx<GenericDataModel>,\n \"runQuery\" | \"runMutation\"\n>;\ntype ComponentReadCtx = Pick<GenericActionCtx<GenericDataModel>, \"runQuery\">;\ntype ComponentAuthReadCtx = ComponentReadCtx & { auth: Auth };\ntype AccountCredentials = { id: string; secret?: string };\ntype CreateAccountArgs = {\n provider: string;\n account: AccountCredentials;\n profile: Record<string, unknown>;\n shouldLinkViaEmail?: boolean;\n shouldLinkViaPhone?: boolean;\n};\ntype RetrieveAccountArgs = { provider: string; account: AccountCredentials };\ntype UpdateAccountCredentialsArgs = {\n provider: string;\n account: { id: string; secret: string };\n};\n\ntype CoreDeps = {\n config: any;\n getAuth: () => any;\n callInvalidateSessions: <DataModel extends GenericDataModel>(\n ctx: GenericActionCtx<DataModel>,\n args: { userId: GenericId<\"User\">; except?: GenericId<\"Session\">[] },\n ) => Promise<void>;\n callCreateAccountFromCredentials: <DataModel extends GenericDataModel>(\n ctx: GenericActionCtx<DataModel>,\n args: CreateAccountArgs,\n ) => Promise<any>;\n callRetrieveAccountWithCredentials: <DataModel extends GenericDataModel>(\n ctx: GenericActionCtx<DataModel>,\n args: RetrieveAccountArgs,\n ) => Promise<any>;\n callModifyAccount: <DataModel extends GenericDataModel>(\n ctx: GenericActionCtx<DataModel>,\n args: UpdateAccountCredentialsArgs,\n ) => Promise<void>;\n getEnrichCtx: () => <DataModel extends GenericDataModel>(\n ctx: GenericActionCtx<DataModel>,\n ) => any;\n inviteTokenAlphabet: string;\n inviteTokenLength: number;\n};\n\n/**\n * Build the core auth domains that back the canonical app API surface.\n */\nexport function createCoreDomains(deps: CoreDeps) {\n const {\n config,\n getAuth,\n callInvalidateSessions,\n callCreateAccountFromCredentials,\n callRetrieveAccountWithCredentials,\n callModifyAccount,\n getEnrichCtx,\n inviteTokenAlphabet,\n inviteTokenLength,\n } = deps;\n\n const roleDefinitions = config.authorization.roles as Record<\n string,\n { label?: string; grants: string[] }\n >;\n\n const getRoleDefinition = (roleId: string) => {\n const role = roleDefinitions[roleId];\n if (!role) {\n throw new AuthError(\n \"INVALID_PARAMETERS\",\n `Unknown roleId \"${roleId}\".`,\n ).toConvexError();\n }\n return role;\n };\n\n const normalizeRoleIds = (roleIds?: string[]) => {\n const normalized = Array.from(new Set(roleIds ?? []));\n for (const roleId of normalized) {\n getRoleDefinition(roleId);\n }\n return normalized;\n };\n\n const resolveGrantedPermissions = (roleIds?: string[]) => {\n const grants = new Set<string>();\n for (const roleId of roleIds ?? []) {\n const role = getRoleDefinition(roleId);\n for (const grant of role.grants) {\n grants.add(grant);\n }\n }\n return Array.from(grants).sort();\n };\n\n const user = {\n current: async (\n ctx: { auth: Auth } & Partial<ComponentCtx>,\n request?: Request,\n ): Promise<string | null> => {\n const identity = await ctx.auth.getUserIdentity();\n if (identity !== null) {\n const [userId] = identity.subject.split(TOKEN_SUB_CLAIM_DIVIDER);\n return userId;\n }\n if (request !== undefined && \"runMutation\" in ctx && ctx.runMutation) {\n const authHeader = request.headers.get(\"Authorization\");\n if (authHeader?.startsWith(\"Bearer sk_\")) {\n const rawKey = authHeader.slice(7);\n try {\n const result = await getAuth().key.verify(\n ctx as ComponentCtx,\n rawKey,\n );\n return result.userId;\n } catch {\n return null;\n }\n }\n }\n return null;\n },\n require: async (\n ctx: { auth: Auth } & Partial<ComponentCtx>,\n request?: Request,\n ): Promise<string> => {\n const userId = await user.current(ctx, request);\n if (userId === null) {\n throw new AuthError(\"NOT_SIGNED_IN\").toConvexError();\n }\n return userId;\n },\n get: async (ctx: ComponentReadCtx, userId: string) => {\n return await ctx.runQuery(config.component.public.userGetById, {\n userId,\n });\n },\n list: async (\n ctx: ComponentReadCtx,\n opts: {\n where?: UserWhere;\n limit?: number;\n cursor?: string | null;\n orderBy?: UserOrderBy;\n order?: \"asc\" | \"desc\";\n } = {},\n ) => {\n return await ctx.runQuery(config.component.public.userList, opts);\n },\n viewer: async (ctx: ComponentAuthReadCtx) => {\n const userId = await user.current(ctx);\n if (userId === null) return null;\n return await ctx.runQuery(config.component.public.userGetById, {\n userId,\n });\n },\n update: async (\n ctx: ComponentCtx,\n userId: string,\n data: Record<string, unknown>,\n ) => {\n await ctx.runMutation(config.component.public.userPatch, {\n userId,\n data,\n });\n return { ok: true as const, userId };\n },\n setActiveGroup: async (\n ctx: ComponentCtx,\n opts: { userId: string; groupId: string | null },\n ) => {\n const doc = await user.get(ctx, opts.userId);\n const existingExtend =\n doc !== null &&\n doc.extend !== null &&\n typeof doc.extend === \"object\" &&\n !Array.isArray(doc.extend)\n ? { ...(doc.extend as Record<string, unknown>) }\n : {};\n if (opts.groupId === null) {\n const { lastActiveGroup: _omit, ...rest } = existingExtend;\n await user.update(ctx, opts.userId, { extend: rest });\n return { ok: true as const, userId: opts.userId, groupId: null };\n }\n await user.update(ctx, opts.userId, {\n extend: { ...existingExtend, lastActiveGroup: opts.groupId },\n });\n return { ok: true as const, userId: opts.userId, groupId: opts.groupId };\n },\n getActiveGroup: async (\n ctx: ComponentReadCtx,\n opts: { userId: string },\n ): Promise<string | null> => {\n const doc = await user.get(ctx, opts.userId);\n if (\n doc !== null &&\n doc.extend !== null &&\n typeof doc.extend === \"object\" &&\n !Array.isArray(doc.extend)\n ) {\n const val = (doc.extend as Record<string, unknown>).lastActiveGroup;\n if (typeof val === \"string\") return val;\n }\n return null;\n },\n delete: async (\n ctx: ComponentCtx,\n userId: string,\n opts?: { cascade?: boolean },\n ) => {\n const cascade = opts?.cascade !== false;\n const [sessions, accounts, keys, members, passkeys, totps] =\n await Promise.all([\n ctx.runQuery(config.component.public.sessionListByUser, {\n userId,\n }) as Promise<Array<{ _id: string }>>,\n ctx.runQuery(config.component.public.accountListByUser, {\n userId,\n }) as Promise<Array<{ _id: string }>>,\n ctx.runQuery(config.component.public.keyListByUserId, {\n userId,\n }) as Promise<Array<{ _id: string }>>,\n ctx.runQuery(config.component.public.memberListByUser, {\n userId,\n }) as Promise<Array<{ _id: string }>>,\n ctx.runQuery(config.component.public.passkeyListByUserId, {\n userId,\n }) as Promise<Array<{ _id: string }>>,\n ctx.runQuery(config.component.public.totpListByUserId, {\n userId,\n }) as Promise<Array<{ _id: string }>>,\n ]);\n const totalLinked =\n sessions.length +\n accounts.length +\n keys.length +\n members.length +\n passkeys.length +\n totps.length;\n if (!cascade && totalLinked > 0) {\n throw new AuthError(\n \"INVALID_PARAMETERS\",\n `Cannot delete user with ${totalLinked} linked records. Pass { cascade: true } to delete all linked records, or remove them manually first.`,\n ).toConvexError();\n }\n const deletions: Promise<unknown>[] = [];\n for (const s of sessions)\n deletions.push(\n ctx.runMutation(config.component.public.sessionDelete, {\n sessionId: s._id,\n }),\n );\n for (const a of accounts)\n deletions.push(\n ctx.runMutation(config.component.public.accountDelete, {\n accountId: a._id,\n }),\n );\n for (const k of keys)\n deletions.push(\n ctx.runMutation(config.component.public.keyDelete, { keyId: k._id }),\n );\n for (const m of members)\n deletions.push(\n ctx.runMutation(config.component.public.memberRemove, {\n memberId: m._id,\n }),\n );\n for (const p of passkeys)\n deletions.push(\n ctx.runMutation(config.component.public.passkeyDelete, {\n passkeyId: p._id,\n }),\n );\n for (const t of totps)\n deletions.push(\n ctx.runMutation(config.component.public.totpDelete, {\n totpId: t._id,\n }),\n );\n await Promise.all(deletions);\n await ctx.runMutation(config.component.public.userDelete, { userId });\n return { ok: true as const, userId };\n },\n };\n\n const session = {\n current: async (ctx: { auth: Auth }) => {\n const identity = await ctx.auth.getUserIdentity();\n if (identity === null) return null;\n const [, sessionId] = identity.subject.split(TOKEN_SUB_CLAIM_DIVIDER);\n return sessionId as GenericId<\"Session\">;\n },\n invalidate: async <DataModel extends GenericDataModel>(\n ctx: GenericActionCtx<DataModel>,\n args: { userId: GenericId<\"User\">; except?: GenericId<\"Session\">[] },\n ) => {\n await callInvalidateSessions(ctx, args);\n return {\n ok: true as const,\n userId: args.userId,\n except: args.except ?? [],\n };\n },\n get: async (ctx: ComponentReadCtx, sessionId: string) => {\n return await ctx.runQuery(config.component.public.sessionGetById, {\n sessionId,\n });\n },\n list: async (ctx: ComponentReadCtx, opts: { userId: string }) => {\n return await ctx.runQuery(config.component.public.sessionListByUser, {\n userId: opts.userId,\n });\n },\n };\n\n const account = {\n create: async <DataModel extends GenericDataModel>(\n ctx: GenericActionCtx<DataModel>,\n args: CreateAccountArgs,\n ) => {\n const created = await callCreateAccountFromCredentials(ctx, args);\n return { ok: true as const, ...created };\n },\n get: async <DataModel extends GenericDataModel>(\n ctx: GenericActionCtx<DataModel>,\n args: RetrieveAccountArgs,\n ) => {\n const result = await callRetrieveAccountWithCredentials(ctx, args);\n if (typeof result === \"string\") {\n throw new AuthError(\"ACCOUNT_NOT_FOUND\", result).toConvexError();\n }\n return result;\n },\n update: async <DataModel extends GenericDataModel>(\n ctx: GenericActionCtx<DataModel>,\n args: UpdateAccountCredentialsArgs,\n ) => {\n await callModifyAccount(ctx, args);\n return { ok: true as const, accountId: args.account.id };\n },\n delete: async (ctx: ComponentCtx, accountId: string) => {\n const doc = await ctx.runQuery(config.component.public.accountGetById, {\n accountId,\n });\n if (doc === null) {\n throw new AuthError(\n \"ACCOUNT_NOT_FOUND\",\n \"Account not found.\",\n ).toConvexError();\n }\n const allAccounts = (await ctx.runQuery(\n config.component.public.accountListByUser,\n { userId: (doc as any).userId },\n )) as Array<{ _id: string }>;\n if (allAccounts.length <= 1) {\n throw new AuthError(\n \"INVALID_PARAMETERS\",\n \"Cannot unlink the user's only account. This would lock them out.\",\n ).toConvexError();\n }\n await ctx.runMutation(config.component.public.accountDelete, {\n accountId,\n });\n return { ok: true as const, accountId };\n },\n listPasskeys: async (ctx: ComponentReadCtx, opts: { userId: string }) => {\n return await ctx.runQuery(\n config.component.public.passkeyListByUserId,\n opts,\n );\n },\n renamePasskey: async (\n ctx: ComponentCtx,\n passkeyId: string,\n name: string,\n ) => {\n await ctx.runMutation(config.component.public.passkeyUpdateMeta, {\n passkeyId,\n data: { name },\n });\n return { ok: true as const, passkeyId };\n },\n deletePasskey: async (ctx: ComponentCtx, passkeyId: string) => {\n await ctx.runMutation(config.component.public.passkeyDelete, {\n passkeyId,\n });\n return { ok: true as const, passkeyId };\n },\n listTotps: async (ctx: ComponentReadCtx, opts: { userId: string }) => {\n return await ctx.runQuery(config.component.public.totpListByUserId, opts);\n },\n deleteTotp: async (ctx: ComponentCtx, totpId: string) => {\n await ctx.runMutation(config.component.public.totpDelete, { totpId });\n return { ok: true as const, totpId };\n },\n };\n\n const provider = {\n signIn: async <DataModel extends GenericDataModel>(\n ctx: GenericActionCtx<DataModel>,\n providerConfig: AuthProviderConfig,\n args: {\n accountId?: GenericId<\"Account\">;\n params?: Record<string, unknown>;\n },\n ) => {\n const result = await signInImpl(\n getEnrichCtx()(ctx),\n materializeProvider(providerConfig),\n args as {\n accountId?: GenericId<\"Account\">;\n params?: Record<string, any>;\n },\n { generateTokens: false, allowExtraProviders: true },\n );\n return result.kind === \"signedIn\"\n ? result.signedIn !== null\n ? {\n userId: result.signedIn.userId,\n sessionId: result.signedIn.sessionId,\n }\n : null\n : null;\n },\n };\n\n const group = {\n create: async (\n ctx: ComponentCtx,\n data: {\n name: string;\n slug?: string;\n type?: string;\n parentGroupId?: string;\n tags?: Array<{ key: string; value: string }>;\n extend?: Record<string, unknown>;\n },\n ): Promise<{ ok: true; groupId: string }> => {\n const groupId = (await ctx.runMutation(\n config.component.public.groupCreate,\n data,\n )) as string;\n return { ok: true, groupId };\n },\n get: async (ctx: ComponentReadCtx, groupId: string) => {\n return await ctx.runQuery(config.component.public.groupGet, { groupId });\n },\n list: async (\n ctx: ComponentReadCtx,\n opts?: {\n where?: {\n slug?: string;\n type?: string;\n parentGroupId?: string;\n name?: string;\n isRoot?: boolean;\n tagsAll?: Array<{ key: string; value: string }>;\n tagsAny?: Array<{ key: string; value: string }>;\n };\n limit?: number;\n cursor?: string | null;\n orderBy?: \"_creationTime\" | \"name\" | \"slug\" | \"type\";\n order?: \"asc\" | \"desc\";\n },\n ) => {\n return await ctx.runQuery(config.component.public.groupList, {\n where: opts?.where,\n limit: opts?.limit,\n cursor: opts?.cursor,\n orderBy: opts?.orderBy,\n order: opts?.order,\n });\n },\n update: async (\n ctx: ComponentCtx,\n groupId: string,\n data: Record<string, unknown>,\n ) => {\n await ctx.runMutation(config.component.public.groupUpdate, {\n groupId,\n data,\n });\n return { ok: true as const, groupId };\n },\n delete: async (ctx: ComponentCtx, groupId: string) => {\n await ctx.runMutation(config.component.public.groupDelete, { groupId });\n return { ok: true as const, groupId };\n },\n ancestors: async (\n ctx: ComponentReadCtx,\n opts: { groupId: string; maxDepth?: number; includeSelf?: boolean },\n ) => {\n const maxDepth = Math.max(0, Math.floor(opts.maxDepth ?? 32));\n const visited = new Set<string>();\n const ancestors: any[] = [];\n let cycleDetected = false;\n let maxDepthReached = false;\n let currentGroupId: string | undefined = opts.groupId;\n let depth = 0;\n let isFirst = true;\n while (currentGroupId !== undefined) {\n if (depth > maxDepth) {\n maxDepthReached = true;\n break;\n }\n if (visited.has(currentGroupId)) {\n cycleDetected = true;\n break;\n }\n visited.add(currentGroupId);\n const doc = await group.get(ctx, currentGroupId);\n if (doc === null) break;\n if (isFirst) {\n isFirst = false;\n if (opts.includeSelf) ancestors.push(doc);\n currentGroupId = doc.parentGroupId;\n depth += 1;\n continue;\n }\n ancestors.push(doc);\n currentGroupId = doc.parentGroupId;\n depth += 1;\n }\n return { ancestors, cycleDetected, maxDepthReached };\n },\n };\n\n const member = {\n create: async (\n ctx: ComponentCtx,\n data: {\n groupId: string;\n userId: string;\n roleIds?: string[];\n status?: string;\n extend?: Record<string, unknown>;\n },\n ): Promise<{ ok: true; memberId: string }> => {\n const roleIds = normalizeRoleIds(data.roleIds);\n const memberId = (await ctx.runMutation(\n config.component.public.memberAdd,\n { ...data, roleIds },\n )) as string;\n return { ok: true, memberId };\n },\n get: async (ctx: ComponentReadCtx, memberId: string) => {\n return await ctx.runQuery(config.component.public.memberGet, {\n memberId,\n });\n },\n getByUserAndGroup: async (\n ctx: ComponentReadCtx,\n opts: { userId: string; groupId: string },\n ) => {\n return await ctx.runQuery(\n config.component.public.memberGetByGroupAndUser,\n opts,\n );\n },\n list: async (\n ctx: ComponentReadCtx,\n opts?: {\n where?: {\n groupId?: string;\n userId?: string;\n roleId?: string;\n status?: string;\n };\n limit?: number;\n cursor?: string | null;\n orderBy?: \"_creationTime\" | \"status\";\n order?: \"asc\" | \"desc\";\n },\n ) => {\n return await ctx.runQuery(config.component.public.memberList, {\n where: opts?.where,\n limit: opts?.limit,\n cursor: opts?.cursor,\n orderBy: opts?.orderBy,\n order: opts?.order,\n });\n },\n delete: async (ctx: ComponentCtx, memberId: string) => {\n await ctx.runMutation(config.component.public.memberRemove, { memberId });\n return { ok: true as const, memberId };\n },\n update: async (\n ctx: ComponentCtx,\n memberId: string,\n data: Record<string, unknown>,\n ) => {\n const nextData = { ...data };\n if (\"roleIds\" in nextData) {\n nextData.roleIds = normalizeRoleIds(\n Array.isArray(nextData.roleIds)\n ? (nextData.roleIds as string[])\n : undefined,\n );\n }\n await ctx.runMutation(config.component.public.memberUpdate, {\n memberId,\n data: nextData,\n });\n return { ok: true as const, memberId };\n },\n inherit: async (\n ctx: ComponentReadCtx,\n opts: {\n userId: string;\n groupId: string;\n roleIds?: string[];\n grants?: string[];\n maxDepth?: number;\n },\n ) => {\n const requestedRoleIds = normalizeRoleIds(opts.roleIds);\n const roleFilter =\n requestedRoleIds.length > 0 ? new Set(requestedRoleIds) : null;\n const requiredGrants = Array.from(new Set(opts.grants ?? []));\n const maxDepth = Math.max(0, Math.floor(opts.maxDepth ?? 32));\n const visited = new Set<string>();\n const traversedGroupIds: string[] = [];\n let currentGroupId: string | undefined = opts.groupId;\n let depth = 0;\n let cycleDetected = false;\n let maxDepthReached = false;\n while (currentGroupId !== undefined) {\n if (depth > maxDepth) {\n maxDepthReached = true;\n break;\n }\n if (visited.has(currentGroupId)) {\n cycleDetected = true;\n break;\n }\n visited.add(currentGroupId);\n traversedGroupIds.push(currentGroupId);\n const membership = await member.getByUserAndGroup(ctx, {\n userId: opts.userId,\n groupId: currentGroupId,\n });\n const membershipRoleIds = membership?.roleIds ?? [];\n const membershipGrants = resolveGrantedPermissions(membershipRoleIds);\n if (\n membership !== null &&\n (roleFilter === null ||\n membershipRoleIds.some((roleId: string) =>\n roleFilter.has(roleId),\n )) &&\n requiredGrants.every((grant) => membershipGrants.includes(grant))\n ) {\n return {\n requestedGroupId: opts.groupId,\n matchedGroupId: currentGroupId,\n membership,\n roleIds: membershipRoleIds,\n grants: membershipGrants,\n missingGrants: [] as string[],\n depth,\n isDirect: depth === 0,\n isInherited: depth > 0,\n traversedGroupIds,\n cycleDetected: false,\n maxDepthReached: false,\n };\n }\n const doc = await group.get(ctx, currentGroupId);\n if (doc === null || doc.parentGroupId === undefined) break;\n currentGroupId = doc.parentGroupId;\n depth += 1;\n }\n return {\n requestedGroupId: opts.groupId,\n matchedGroupId: null,\n membership: null,\n roleIds: [] as string[],\n grants: [] as string[],\n missingGrants: requiredGrants,\n depth: null,\n isDirect: false,\n isInherited: false,\n traversedGroupIds,\n cycleDetected,\n maxDepthReached,\n };\n },\n require: async (\n ctx: ComponentReadCtx,\n opts: {\n userId: string;\n groupId: string;\n roleIds?: string[];\n grants?: string[];\n maxDepth?: number;\n },\n ) => {\n const result = await member.inherit(ctx, opts);\n if (result.membership === null) {\n throw new AuthError(\n \"FORBIDDEN\",\n `User ${opts.userId} has no membership on group ${opts.groupId} or its ancestors.`,\n ).toConvexError();\n }\n return {\n membership: result.membership,\n matchedGroupId: result.matchedGroupId,\n roleIds: result.roleIds,\n grants: result.grants,\n isDirect: result.isDirect,\n isInherited: result.isInherited,\n depth: result.depth,\n };\n },\n };\n\n const access = {\n check: async (\n ctx: ComponentReadCtx,\n opts: {\n userId: string;\n groupId: string;\n grants: string[];\n maxDepth?: number;\n },\n ) => {\n const requiredGrants = Array.from(new Set(opts.grants));\n const result = await member.inherit(ctx, {\n userId: opts.userId,\n groupId: opts.groupId,\n grants: requiredGrants,\n maxDepth: opts.maxDepth,\n });\n const missingGrants = requiredGrants.filter(\n (grant) => !result.grants.includes(grant),\n );\n return {\n ok: result.membership !== null && missingGrants.length === 0,\n membership: result.membership,\n matchedGroupId: result.matchedGroupId,\n roleIds: result.roleIds,\n grants: result.grants,\n missingGrants,\n isDirect: result.isDirect,\n isInherited: result.isInherited,\n depth: result.depth,\n };\n },\n require: async (\n ctx: ComponentReadCtx,\n opts: {\n userId: string;\n groupId: string;\n grants: string[];\n maxDepth?: number;\n },\n ) => {\n const result = await access.check(ctx, opts);\n if (!result.ok) {\n throw new AuthError(\n \"FORBIDDEN\",\n `User ${opts.userId} is missing required grants on group ${opts.groupId}: ${result.missingGrants.join(\", \")}.`,\n ).toConvexError();\n }\n return result;\n },\n };\n\n const invite = {\n create: async (\n ctx: ComponentCtx,\n data: {\n groupId?: string;\n invitedByUserId?: string;\n email?: string;\n roleIds?: string[];\n expiresTime?: number;\n extend?: Record<string, unknown>;\n },\n ): Promise<{ ok: true; inviteId: string; token: string }> => {\n const roleIds = normalizeRoleIds(data.roleIds);\n const token = generateRandomString(\n inviteTokenLength,\n inviteTokenAlphabet,\n );\n const tokenHash = await sha256(token);\n const inviteId = (await ctx.runMutation(\n config.component.public.inviteCreate,\n { ...data, roleIds, tokenHash, status: \"pending\" },\n )) as string;\n return { ok: true, inviteId, token };\n },\n get: async (ctx: ComponentReadCtx, inviteId: string) => {\n return await ctx.runQuery(config.component.public.inviteGet, {\n inviteId,\n });\n },\n token: {\n get: async (ctx: ComponentReadCtx, token: string) => {\n const tokenHash = await sha256(token);\n return await ctx.runQuery(\n config.component.public.inviteGetByTokenHash,\n { tokenHash },\n );\n },\n accept: async (\n ctx: ComponentCtx,\n args: { token: string; acceptedByUserId: string },\n ) => {\n const tokenHash = await sha256(args.token);\n const result = await ctx.runMutation(\n config.component.public.inviteAcceptByToken,\n { tokenHash, acceptedByUserId: args.acceptedByUserId },\n );\n return { ok: true as const, ...result };\n },\n },\n list: async (\n ctx: ComponentReadCtx,\n opts?: {\n where?: {\n tokenHash?: string;\n groupId?: string;\n status?: \"pending\" | \"accepted\" | \"revoked\" | \"expired\";\n email?: string;\n invitedByUserId?: string;\n roleId?: string;\n acceptedByUserId?: string;\n };\n limit?: number;\n cursor?: string | null;\n orderBy?:\n | \"_creationTime\"\n | \"status\"\n | \"email\"\n | \"expiresTime\"\n | \"acceptedTime\";\n order?: \"asc\" | \"desc\";\n },\n ) => {\n return await ctx.runQuery(config.component.public.inviteList, {\n where: opts?.where,\n limit: opts?.limit,\n cursor: opts?.cursor,\n orderBy: opts?.orderBy,\n order: opts?.order,\n });\n },\n accept: async (\n ctx: ComponentCtx,\n inviteId: string,\n acceptedByUserId?: string,\n ) => {\n await ctx.runMutation(config.component.public.inviteAccept, {\n inviteId,\n ...(acceptedByUserId ? { acceptedByUserId } : {}),\n });\n return {\n ok: true as const,\n inviteId,\n acceptedByUserId: acceptedByUserId ?? null,\n };\n },\n revoke: async (ctx: ComponentCtx, inviteId: string) => {\n await ctx.runMutation(config.component.public.inviteRevoke, { inviteId });\n return { ok: true as const, inviteId };\n },\n };\n\n const key = {\n create: async (\n ctx: ComponentCtx,\n opts: {\n userId: string;\n name: string;\n scopes: KeyScope[];\n rateLimit?: { maxRequests: number; windowMs: number };\n expiresAt?: number;\n metadata?: Record<string, unknown>;\n },\n ): Promise<{ ok: true; keyId: string; secret: string }> => {\n const { raw, hashedKey, displayPrefix } = await generateApiKey(\"sk_\");\n const keyId = (await ctx.runMutation(config.component.public.keyInsert, {\n userId: opts.userId,\n prefix: displayPrefix,\n hashedKey,\n name: opts.name,\n scopes: opts.scopes,\n rateLimit: opts.rateLimit,\n expiresAt: opts.expiresAt,\n metadata: opts.metadata,\n })) as string;\n return { ok: true, keyId, secret: raw };\n },\n verify: async (\n ctx: ComponentCtx,\n rawKey: string,\n ): Promise<{ userId: string; keyId: string; scopes: ScopeChecker }> => {\n const hashedKey = await hashApiKey(rawKey);\n const doc = (await ctx.runQuery(\n config.component.public.keyGetByHashedKey,\n { hashedKey },\n )) as KeyDoc | null;\n return Fx.run(\n Fx.gen(function* () {\n yield* Fx.guard(!doc, Fx.fail(new AuthError(\"INVALID_API_KEY\")));\n const k = doc!;\n yield* Fx.guard(k.revoked, Fx.fail(new AuthError(\"API_KEY_REVOKED\")));\n yield* Fx.guard(\n !!(k.expiresAt && k.expiresAt < Date.now()),\n Fx.fail(new AuthError(\"API_KEY_EXPIRED\")),\n );\n const patchData: Record<string, unknown> = { lastUsedAt: Date.now() };\n if (k.rateLimit) {\n const { limited, newState } = checkKeyRateLimit(\n k.rateLimit,\n k.rateLimitState ?? undefined,\n );\n yield* Fx.guard(\n limited,\n Fx.fail(new AuthError(\"API_KEY_RATE_LIMITED\")),\n );\n patchData.rateLimitState = newState;\n }\n yield* Fx.promise(() =>\n ctx.runMutation(config.component.public.keyPatch, {\n keyId: k._id,\n data: patchData,\n }),\n );\n return {\n userId: k.userId,\n keyId: k._id,\n scopes: buildScopeChecker(k.scopes),\n };\n }).pipe(Fx.recover((e) => Fx.fatal(e.toConvexError()))),\n );\n },\n list: async (\n ctx: ComponentReadCtx,\n opts?: {\n where?: {\n userId?: string;\n revoked?: boolean;\n name?: string;\n prefix?: string;\n };\n limit?: number;\n cursor?: string | null;\n orderBy?:\n | \"_creationTime\"\n | \"name\"\n | \"lastUsedAt\"\n | \"expiresAt\"\n | \"revoked\";\n order?: \"asc\" | \"desc\";\n },\n ) => {\n return await ctx.runQuery(config.component.public.keyList, {\n where: opts?.where,\n limit: opts?.limit,\n cursor: opts?.cursor,\n orderBy: opts?.orderBy,\n order: opts?.order,\n });\n },\n get: async (\n ctx: ComponentReadCtx,\n keyId: string,\n ): Promise<KeyDoc | null> => {\n return (await ctx.runQuery(config.component.public.keyGetById, {\n keyId,\n })) as KeyDoc | null;\n },\n update: async (\n ctx: ComponentCtx,\n keyId: string,\n data: {\n name?: string;\n scopes?: KeyScope[];\n rateLimit?: { maxRequests: number; windowMs: number };\n },\n ) => {\n await ctx.runMutation(config.component.public.keyPatch, { keyId, data });\n return { ok: true as const, keyId };\n },\n revoke: async (ctx: ComponentCtx, keyId: string) => {\n await ctx.runMutation(config.component.public.keyPatch, {\n keyId,\n data: { revoked: true },\n });\n return { ok: true as const, keyId };\n },\n delete: async (ctx: ComponentCtx, keyId: string) => {\n await ctx.runMutation(config.component.public.keyDelete, { keyId });\n return { ok: true as const, keyId };\n },\n rotate: async (\n ctx: ComponentCtx,\n keyId: string,\n opts?: { name?: string; expiresAt?: number },\n ): Promise<{ ok: true; keyId: string; secret: string }> => {\n const existing = await ctx.runQuery(config.component.public.keyGetById, {\n keyId,\n });\n if (!existing)\n throw new AuthError(\n \"INVALID_PARAMETERS\",\n \"API key not found.\",\n ).toConvexError();\n if ((existing as any).revoked === true) {\n throw new AuthError(\n \"API_KEY_REVOKED\",\n \"Cannot rotate a key that is already revoked.\",\n ).toConvexError();\n }\n await ctx.runMutation(config.component.public.keyPatch, {\n keyId,\n data: { revoked: true },\n });\n return await key.create(ctx, {\n userId: (existing as any).userId,\n name: opts?.name ?? (existing as any).name,\n scopes: (existing as any).scopes ?? [],\n rateLimit: (existing as any).rateLimit,\n expiresAt: opts?.expiresAt,\n metadata: (existing as any).metadata,\n });\n },\n };\n\n return {\n user,\n session,\n account,\n provider,\n group,\n member,\n access,\n invite,\n key,\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"core.js","names":[],"sources":["../../../../src/server/domains/core.ts"],"sourcesContent":["import { Auth, GenericActionCtx, GenericDataModel } from \"convex/server\";\nimport { GenericId } from \"convex/values\";\n\nimport {\n buildScopeChecker,\n checkKeyRateLimit,\n generateApiKey,\n hashApiKey,\n} from \"../keys\";\nimport { materializeProvider } from \"../providers\";\nimport { signInImpl } from \"../signin\";\nimport type {\n AuthProviderConfig,\n KeyDoc,\n KeyScope,\n ScopeChecker,\n UserOrderBy,\n UserWhere,\n} from \"../types\";\nimport {\n generateRandomString,\n sha256,\n TOKEN_SUB_CLAIM_DIVIDER,\n} from \"../utils\";\n\ntype ComponentCtx = Pick<\n GenericActionCtx<GenericDataModel>,\n \"runQuery\" | \"runMutation\"\n>;\ntype ComponentReadCtx = Pick<GenericActionCtx<GenericDataModel>, \"runQuery\">;\ntype ComponentAuthReadCtx = ComponentReadCtx & { auth: Auth };\ntype AccountCredentials = { id: string; secret?: string };\ntype CreateAccountArgs = {\n provider: string;\n account: AccountCredentials;\n profile: Record<string, unknown>;\n shouldLinkViaEmail?: boolean;\n shouldLinkViaPhone?: boolean;\n};\ntype RetrieveAccountArgs = { provider: string; account: AccountCredentials };\ntype UpdateAccountCredentialsArgs = {\n provider: string;\n account: { id: string; secret: string };\n};\n\ntype CoreDeps = {\n config: any;\n getAuth: () => any;\n callInvalidateSessions: <DataModel extends GenericDataModel>(\n ctx: GenericActionCtx<DataModel>,\n args: { userId: GenericId<\"User\">; except?: GenericId<\"Session\">[] },\n ) => Promise<void>;\n callCreateAccountFromCredentials: <DataModel extends GenericDataModel>(\n ctx: GenericActionCtx<DataModel>,\n args: CreateAccountArgs,\n ) => Promise<any>;\n callRetrieveAccountWithCredentials: <DataModel extends GenericDataModel>(\n ctx: GenericActionCtx<DataModel>,\n args: RetrieveAccountArgs,\n ) => Promise<any>;\n callModifyAccount: <DataModel extends GenericDataModel>(\n ctx: GenericActionCtx<DataModel>,\n args: UpdateAccountCredentialsArgs,\n ) => Promise<void>;\n getEnrichCtx: () => <DataModel extends GenericDataModel>(\n ctx: GenericActionCtx<DataModel>,\n ) => any;\n inviteTokenAlphabet: string;\n inviteTokenLength: number;\n};\n\n/**\n * Build the core auth domains that back the canonical app API surface.\n */\nexport function createCoreDomains(deps: CoreDeps) {\n const {\n config,\n getAuth,\n callInvalidateSessions,\n callCreateAccountFromCredentials,\n callRetrieveAccountWithCredentials,\n callModifyAccount,\n getEnrichCtx,\n inviteTokenAlphabet,\n inviteTokenLength,\n } = deps;\n\n const roleDefinitions = config.authorization.roles as Record<\n string,\n { label?: string; grants: string[] }\n >;\n\n const getRoleDefinition = (roleId: string) => {\n return roleDefinitions[roleId] ?? null;\n };\n\n const normalizeRoleIds = (\n roleIds?: string[],\n ):\n | { ok: true; roleIds: string[] }\n | { ok: false; invalidRoleIds: string[] } => {\n const normalized = Array.from(new Set(roleIds ?? []));\n const invalid = normalized.filter((id) => getRoleDefinition(id) === null);\n if (invalid.length > 0) {\n return { ok: false, invalidRoleIds: invalid };\n }\n return { ok: true, roleIds: normalized };\n };\n\n const resolveGrantedPermissions = (roleIds?: string[]) => {\n const grants = new Set<string>();\n for (const roleId of roleIds ?? []) {\n const role = getRoleDefinition(roleId);\n if (role === null) continue;\n for (const grant of role.grants) {\n grants.add(grant);\n }\n }\n return Array.from(grants).sort();\n };\n\n // Per-execution cache — attached to ctx so each function invocation has its own.\n // Eliminates redundant cross-component RPCs for the same entity within a handler.\n type CtxCache = {\n users: Map<string, any>;\n groups: Map<string, any>;\n };\n const AUTH_CACHE = Symbol(\"__convexAuthCache\");\n function cache(ctx: any): CtxCache {\n if (!ctx[AUTH_CACHE]) {\n ctx[AUTH_CACHE] = {\n users: new Map(),\n groups: new Map(),\n } satisfies CtxCache;\n }\n return ctx[AUTH_CACHE];\n }\n\n const user = {\n id: async (\n ctx: { auth: Auth } & Partial<ComponentCtx>,\n request?: Request,\n ): Promise<string | null> => {\n const identity = await ctx.auth.getUserIdentity();\n if (identity !== null) {\n const [userId] = identity.subject.split(TOKEN_SUB_CLAIM_DIVIDER);\n return userId;\n }\n if (request !== undefined && \"runMutation\" in ctx && ctx.runMutation) {\n const authHeader = request.headers.get(\"Authorization\");\n if (authHeader?.startsWith(\"Bearer sk_\")) {\n const rawKey = authHeader.slice(7);\n const result = await getAuth().key.verify(\n ctx as ComponentCtx,\n rawKey,\n );\n if (result.ok) {\n return result.userId;\n }\n return null;\n }\n }\n return null;\n },\n get: async (ctx: ComponentReadCtx, userId: string) => {\n const c = cache(ctx);\n if (c.users.has(userId)) return c.users.get(userId);\n const result = await ctx.runQuery(config.component.public.userGetById, {\n userId,\n });\n c.users.set(userId, result);\n return result;\n },\n list: async (\n ctx: ComponentReadCtx,\n opts: {\n where?: UserWhere;\n limit?: number;\n cursor?: string | null;\n orderBy?: UserOrderBy;\n order?: \"asc\" | \"desc\";\n } = {},\n ) => {\n return await ctx.runQuery(config.component.public.userList, opts);\n },\n viewer: async (ctx: ComponentAuthReadCtx) => {\n const userId = await user.id(ctx);\n if (userId === null) return null;\n return await user.get(ctx, userId);\n },\n update: async (\n ctx: ComponentCtx,\n userId: string,\n data: Record<string, unknown>,\n ) => {\n await ctx.runMutation(config.component.public.userPatch, {\n userId,\n data,\n });\n return { ok: true as const, userId };\n },\n setActiveGroup: async (\n ctx: ComponentCtx,\n opts: { userId: string; groupId: string | null },\n ) => {\n const doc = await user.get(ctx, opts.userId);\n const existingExtend =\n doc !== null &&\n doc.extend !== null &&\n typeof doc.extend === \"object\" &&\n !Array.isArray(doc.extend)\n ? { ...(doc.extend as Record<string, unknown>) }\n : {};\n if (opts.groupId === null) {\n const { lastActiveGroup: _omit, ...rest } = existingExtend;\n await user.update(ctx, opts.userId, { extend: rest });\n return { ok: true as const, userId: opts.userId, groupId: null };\n }\n await user.update(ctx, opts.userId, {\n extend: { ...existingExtend, lastActiveGroup: opts.groupId },\n });\n return { ok: true as const, userId: opts.userId, groupId: opts.groupId };\n },\n getActiveGroup: async (\n ctx: ComponentReadCtx,\n opts: { userId: string },\n ): Promise<string | null> => {\n const doc = await user.get(ctx, opts.userId);\n if (\n doc !== null &&\n doc.extend !== null &&\n typeof doc.extend === \"object\" &&\n !Array.isArray(doc.extend)\n ) {\n const val = (doc.extend as Record<string, unknown>).lastActiveGroup;\n if (typeof val === \"string\") return val;\n }\n return null;\n },\n delete: async (\n ctx: ComponentCtx,\n userId: string,\n opts?: { cascade?: boolean },\n ) => {\n const cascade = opts?.cascade !== false;\n const [sessions, accounts, keys, members, passkeys, totps] =\n await Promise.all([\n ctx.runQuery(config.component.public.sessionListByUser, {\n userId,\n }) as Promise<Array<{ _id: string }>>,\n ctx.runQuery(config.component.public.accountListByUser, {\n userId,\n }) as Promise<Array<{ _id: string }>>,\n ctx.runQuery(config.component.public.keyListByUserId, {\n userId,\n }) as Promise<Array<{ _id: string }>>,\n ctx.runQuery(config.component.public.memberListByUser, {\n userId,\n }) as Promise<Array<{ _id: string }>>,\n ctx.runQuery(config.component.public.passkeyListByUserId, {\n userId,\n }) as Promise<Array<{ _id: string }>>,\n ctx.runQuery(config.component.public.totpListByUserId, {\n userId,\n }) as Promise<Array<{ _id: string }>>,\n ]);\n const totalLinked =\n sessions.length +\n accounts.length +\n keys.length +\n members.length +\n passkeys.length +\n totps.length;\n if (!cascade && totalLinked > 0) {\n return { ok: false as const, code: \"INVALID_PARAMETERS\" as const };\n }\n const deletions: Promise<unknown>[] = [];\n for (const s of sessions)\n deletions.push(\n ctx.runMutation(config.component.public.sessionDelete, {\n sessionId: s._id,\n }),\n );\n for (const a of accounts)\n deletions.push(\n ctx.runMutation(config.component.public.accountDelete, {\n accountId: a._id,\n }),\n );\n for (const k of keys)\n deletions.push(\n ctx.runMutation(config.component.public.keyDelete, { keyId: k._id }),\n );\n for (const m of members)\n deletions.push(\n ctx.runMutation(config.component.public.memberRemove, {\n memberId: m._id,\n }),\n );\n for (const p of passkeys)\n deletions.push(\n ctx.runMutation(config.component.public.passkeyDelete, {\n passkeyId: p._id,\n }),\n );\n for (const t of totps)\n deletions.push(\n ctx.runMutation(config.component.public.totpDelete, {\n totpId: t._id,\n }),\n );\n await Promise.all(deletions);\n await ctx.runMutation(config.component.public.userDelete, { userId });\n return { ok: true as const, userId };\n },\n };\n\n const session = {\n current: async (ctx: { auth: Auth }) => {\n const identity = await ctx.auth.getUserIdentity();\n if (identity === null) return null;\n const [, sessionId] = identity.subject.split(TOKEN_SUB_CLAIM_DIVIDER);\n return sessionId as GenericId<\"Session\">;\n },\n invalidate: async <DataModel extends GenericDataModel>(\n ctx: GenericActionCtx<DataModel>,\n args: { userId: GenericId<\"User\">; except?: GenericId<\"Session\">[] },\n ) => {\n await callInvalidateSessions(ctx, args);\n return {\n ok: true as const,\n userId: args.userId,\n except: args.except ?? [],\n };\n },\n get: async (ctx: ComponentReadCtx, sessionId: string) => {\n return await ctx.runQuery(config.component.public.sessionGetById, {\n sessionId,\n });\n },\n list: async (ctx: ComponentReadCtx, opts: { userId: string }) => {\n return await ctx.runQuery(config.component.public.sessionListByUser, {\n userId: opts.userId,\n });\n },\n };\n\n const account = {\n create: async <DataModel extends GenericDataModel>(\n ctx: GenericActionCtx<DataModel>,\n args: CreateAccountArgs,\n ) => {\n const created = await callCreateAccountFromCredentials(ctx, args);\n return { ok: true as const, ...created };\n },\n get: async <DataModel extends GenericDataModel>(\n ctx: GenericActionCtx<DataModel>,\n args: RetrieveAccountArgs,\n ) => {\n const result = await callRetrieveAccountWithCredentials(ctx, args);\n if (typeof result === \"string\") {\n return null;\n }\n return result;\n },\n update: async <DataModel extends GenericDataModel>(\n ctx: GenericActionCtx<DataModel>,\n args: UpdateAccountCredentialsArgs,\n ) => {\n await callModifyAccount(ctx, args);\n return { ok: true as const, accountId: args.account.id };\n },\n delete: async (ctx: ComponentCtx, accountId: string) => {\n const doc = await ctx.runQuery(config.component.public.accountGetById, {\n accountId,\n });\n if (doc === null) {\n return { ok: false as const, code: \"ACCOUNT_NOT_FOUND\" as const };\n }\n const allAccounts = (await ctx.runQuery(\n config.component.public.accountListByUser,\n { userId: (doc as any).userId },\n )) as Array<{ _id: string }>;\n if (allAccounts.length <= 1) {\n return { ok: false as const, code: \"INVALID_PARAMETERS\" as const };\n }\n await ctx.runMutation(config.component.public.accountDelete, {\n accountId,\n });\n return { ok: true as const, accountId };\n },\n listPasskeys: async (ctx: ComponentReadCtx, opts: { userId: string }) => {\n return await ctx.runQuery(\n config.component.public.passkeyListByUserId,\n opts,\n );\n },\n renamePasskey: async (\n ctx: ComponentCtx,\n passkeyId: string,\n name: string,\n ) => {\n await ctx.runMutation(config.component.public.passkeyUpdateMeta, {\n passkeyId,\n data: { name },\n });\n return { ok: true as const, passkeyId };\n },\n deletePasskey: async (ctx: ComponentCtx, passkeyId: string) => {\n await ctx.runMutation(config.component.public.passkeyDelete, {\n passkeyId,\n });\n return { ok: true as const, passkeyId };\n },\n listTotps: async (ctx: ComponentReadCtx, opts: { userId: string }) => {\n return await ctx.runQuery(config.component.public.totpListByUserId, opts);\n },\n deleteTotp: async (ctx: ComponentCtx, totpId: string) => {\n await ctx.runMutation(config.component.public.totpDelete, { totpId });\n return { ok: true as const, totpId };\n },\n };\n\n const provider = {\n signIn: async <DataModel extends GenericDataModel>(\n ctx: GenericActionCtx<DataModel>,\n providerConfig: AuthProviderConfig,\n args: {\n accountId?: GenericId<\"Account\">;\n params?: Record<string, unknown>;\n },\n ) => {\n const result = await signInImpl(\n getEnrichCtx()(ctx),\n materializeProvider(providerConfig),\n args as {\n accountId?: GenericId<\"Account\">;\n params?: Record<string, any>;\n },\n { generateTokens: false, allowExtraProviders: true },\n );\n return result.kind === \"signedIn\"\n ? result.signedIn !== null\n ? {\n userId: result.signedIn.userId,\n sessionId: result.signedIn.sessionId,\n }\n : null\n : null;\n },\n };\n\n const group = {\n create: async (\n ctx: ComponentCtx,\n data: {\n name: string;\n slug?: string;\n type?: string;\n parentGroupId?: string;\n tags?: Array<{ key: string; value: string }>;\n extend?: Record<string, unknown>;\n },\n ): Promise<{ ok: true; groupId: string }> => {\n const groupId = (await ctx.runMutation(\n config.component.public.groupCreate,\n data,\n )) as string;\n return { ok: true, groupId };\n },\n get: async (ctx: ComponentReadCtx, groupId: string) => {\n const c = cache(ctx);\n if (c.groups.has(groupId)) return c.groups.get(groupId);\n const result = await ctx.runQuery(config.component.public.groupGet, {\n groupId,\n });\n c.groups.set(groupId, result);\n return result;\n },\n list: async (\n ctx: ComponentReadCtx,\n opts?: {\n where?: {\n slug?: string;\n type?: string;\n parentGroupId?: string;\n name?: string;\n isRoot?: boolean;\n tagsAll?: Array<{ key: string; value: string }>;\n tagsAny?: Array<{ key: string; value: string }>;\n };\n limit?: number;\n cursor?: string | null;\n orderBy?: \"_creationTime\" | \"name\" | \"slug\" | \"type\";\n order?: \"asc\" | \"desc\";\n },\n ) => {\n return await ctx.runQuery(config.component.public.groupList, {\n where: opts?.where,\n limit: opts?.limit,\n cursor: opts?.cursor,\n orderBy: opts?.orderBy,\n order: opts?.order,\n });\n },\n update: async (\n ctx: ComponentCtx,\n groupId: string,\n data: Record<string, unknown>,\n ) => {\n await ctx.runMutation(config.component.public.groupUpdate, {\n groupId,\n data,\n });\n return { ok: true as const, groupId };\n },\n delete: async (ctx: ComponentCtx, groupId: string) => {\n await ctx.runMutation(config.component.public.groupDelete, { groupId });\n return { ok: true as const, groupId };\n },\n ancestors: async (\n ctx: ComponentReadCtx,\n opts: { groupId: string; maxDepth?: number; includeSelf?: boolean },\n ) => {\n const maxDepth = Math.max(0, Math.floor(opts.maxDepth ?? 32));\n const visited = new Set<string>();\n const ancestors: any[] = [];\n let cycleDetected = false;\n let maxDepthReached = false;\n let currentGroupId: string | undefined = opts.groupId;\n let depth = 0;\n let isFirst = true;\n while (currentGroupId !== undefined) {\n if (depth > maxDepth) {\n maxDepthReached = true;\n break;\n }\n if (visited.has(currentGroupId)) {\n cycleDetected = true;\n break;\n }\n visited.add(currentGroupId);\n const doc = await group.get(ctx, currentGroupId);\n if (doc === null) break;\n if (isFirst) {\n isFirst = false;\n if (opts.includeSelf) ancestors.push(doc);\n currentGroupId = doc.parentGroupId;\n depth += 1;\n continue;\n }\n ancestors.push(doc);\n currentGroupId = doc.parentGroupId;\n depth += 1;\n }\n return { ancestors, cycleDetected, maxDepthReached };\n },\n };\n\n const member = {\n create: async (\n ctx: ComponentCtx,\n data: {\n groupId: string;\n userId: string;\n roleIds?: string[];\n status?: string;\n extend?: Record<string, unknown>;\n },\n ) => {\n const normalized = normalizeRoleIds(data.roleIds);\n if (!normalized.ok)\n return {\n ok: false as const,\n code: \"INVALID_ROLE_IDS\" as const,\n invalidRoleIds: normalized.invalidRoleIds,\n };\n const memberId = (await ctx.runMutation(\n config.component.public.memberAdd,\n { ...data, roleIds: normalized.roleIds },\n )) as string;\n return { ok: true as const, memberId };\n },\n get: async (ctx: ComponentReadCtx, memberId: string) => {\n return await ctx.runQuery(config.component.public.memberGet, {\n memberId,\n });\n },\n getByUserAndGroup: async (\n ctx: ComponentReadCtx,\n opts: { userId: string; groupId: string },\n ) => {\n return await ctx.runQuery(\n config.component.public.memberGetByGroupAndUser,\n opts,\n );\n },\n list: async (\n ctx: ComponentReadCtx,\n opts?: {\n where?: {\n groupId?: string;\n userId?: string;\n roleId?: string;\n status?: string;\n };\n limit?: number;\n cursor?: string | null;\n orderBy?: \"_creationTime\" | \"status\";\n order?: \"asc\" | \"desc\";\n },\n ) => {\n return await ctx.runQuery(config.component.public.memberList, {\n where: opts?.where,\n limit: opts?.limit,\n cursor: opts?.cursor,\n orderBy: opts?.orderBy,\n order: opts?.order,\n });\n },\n delete: async (ctx: ComponentCtx, memberId: string) => {\n await ctx.runMutation(config.component.public.memberRemove, { memberId });\n return { ok: true as const, memberId };\n },\n update: async (\n ctx: ComponentCtx,\n memberId: string,\n data: Record<string, unknown>,\n ) => {\n const nextData = { ...data };\n if (\"roleIds\" in nextData) {\n const normalized = normalizeRoleIds(\n Array.isArray(nextData.roleIds)\n ? (nextData.roleIds as string[])\n : undefined,\n );\n if (!normalized.ok)\n return {\n ok: false as const,\n code: \"INVALID_ROLE_IDS\" as const,\n invalidRoleIds: normalized.invalidRoleIds,\n };\n nextData.roleIds = normalized.roleIds;\n }\n await ctx.runMutation(config.component.public.memberUpdate, {\n memberId,\n data: nextData,\n });\n return { ok: true as const, memberId };\n },\n resolve: async (\n ctx: ComponentReadCtx,\n opts: {\n userId: string;\n groupId: string;\n roleIds?: string[];\n grants?: string[];\n maxDepth?: number;\n },\n ) => {\n const normalized = normalizeRoleIds(opts.roleIds);\n if (!normalized.ok)\n return {\n ok: false as const,\n code: \"INVALID_ROLE_IDS\" as const,\n invalidRoleIds: normalized.invalidRoleIds,\n };\n const requestedRoleIds = normalized.roleIds;\n const roleFilter =\n requestedRoleIds.length > 0 ? new Set(requestedRoleIds) : null;\n const requiredGrants = Array.from(new Set(opts.grants ?? []));\n const maxDepth = Math.max(0, Math.floor(opts.maxDepth ?? 32));\n\n // Single cross-component RPC — hierarchy walk happens inside the component\n const result = await ctx.runQuery(config.component.public.memberResolve, {\n userId: opts.userId,\n groupId: opts.groupId,\n maxDepth,\n ancestry: true,\n });\n\n const traversedGroupIds = result.traversedGroupIds ?? [];\n\n if (result.membership === null) {\n return {\n requestedGroupId: opts.groupId,\n matchedGroupId: null,\n membership: null,\n roleIds: [] as string[],\n grants: [] as string[],\n missingGrants: requiredGrants,\n depth: null,\n isDirect: false,\n isInherited: false,\n traversedGroupIds,\n cycleDetected: false,\n maxDepthReached: false,\n };\n }\n\n // Grant resolution uses app-defined roles — stays server-side\n const membershipRoleIds = (result.membership as any).roleIds ?? [];\n const membershipGrants = resolveGrantedPermissions(membershipRoleIds);\n\n // Check role filter\n if (\n roleFilter !== null &&\n !membershipRoleIds.some((roleId: string) => roleFilter.has(roleId))\n ) {\n return {\n requestedGroupId: opts.groupId,\n matchedGroupId: null,\n membership: null,\n roleIds: [] as string[],\n grants: [] as string[],\n missingGrants: requiredGrants,\n depth: null,\n isDirect: false,\n isInherited: false,\n traversedGroupIds,\n cycleDetected: false,\n maxDepthReached: false,\n };\n }\n\n // Check required grants\n const missingGrants = requiredGrants.filter(\n (grant) => !membershipGrants.includes(grant),\n );\n if (missingGrants.length > 0) {\n return {\n requestedGroupId: opts.groupId,\n matchedGroupId: result.matchedGroupId,\n membership: result.membership,\n roleIds: membershipRoleIds,\n grants: membershipGrants,\n missingGrants,\n depth: result.depth,\n isDirect: result.isDirect,\n isInherited: result.isInherited,\n traversedGroupIds,\n cycleDetected: false,\n maxDepthReached: false,\n };\n }\n\n return {\n requestedGroupId: opts.groupId,\n matchedGroupId: result.matchedGroupId,\n membership: result.membership,\n roleIds: membershipRoleIds,\n grants: membershipGrants,\n missingGrants: [] as string[],\n depth: result.depth,\n isDirect: result.isDirect,\n isInherited: result.isInherited,\n traversedGroupIds,\n cycleDetected: false,\n maxDepthReached: false,\n };\n },\n };\n\n const access = {\n check: async (\n ctx: ComponentReadCtx,\n opts: {\n userId: string;\n groupId: string;\n grants: string[];\n maxDepth?: number;\n },\n ) => {\n const requiredGrants = Array.from(new Set(opts.grants));\n const result = await member.resolve(ctx, {\n userId: opts.userId,\n groupId: opts.groupId,\n grants: requiredGrants,\n maxDepth: opts.maxDepth,\n });\n if (\"code\" in result && result.code === \"INVALID_ROLE_IDS\") {\n return {\n ok: false,\n membership: null,\n matchedGroupId: null,\n roleIds: [] as string[],\n grants: [] as string[],\n missingGrants: requiredGrants,\n isDirect: false,\n isInherited: false,\n depth: null,\n };\n }\n const missingGrants = requiredGrants.filter(\n (grant) => !result.grants.includes(grant),\n );\n return {\n ok: result.membership !== null && missingGrants.length === 0,\n membership: result.membership,\n matchedGroupId: result.matchedGroupId,\n roleIds: result.roleIds,\n grants: result.grants,\n missingGrants,\n isDirect: result.isDirect,\n isInherited: result.isInherited,\n depth: result.depth,\n };\n },\n };\n\n const invite = {\n create: async (\n ctx: ComponentCtx,\n data: {\n groupId?: string;\n invitedByUserId?: string;\n email?: string;\n roleIds?: string[];\n expiresTime?: number;\n extend?: Record<string, unknown>;\n },\n ) => {\n const normalized = normalizeRoleIds(data.roleIds);\n if (!normalized.ok)\n return {\n ok: false as const,\n code: \"INVALID_ROLE_IDS\" as const,\n invalidRoleIds: normalized.invalidRoleIds,\n };\n const token = generateRandomString(\n inviteTokenLength,\n inviteTokenAlphabet,\n );\n const tokenHash = await sha256(token);\n const inviteId = (await ctx.runMutation(\n config.component.public.inviteCreate,\n { ...data, roleIds: normalized.roleIds, tokenHash, status: \"pending\" },\n )) as string;\n return { ok: true as const, inviteId, token };\n },\n get: async (ctx: ComponentReadCtx, inviteId: string) => {\n return await ctx.runQuery(config.component.public.inviteGet, {\n inviteId,\n });\n },\n token: {\n get: async (ctx: ComponentReadCtx, token: string) => {\n const tokenHash = await sha256(token);\n return await ctx.runQuery(\n config.component.public.inviteGetByTokenHash,\n { tokenHash },\n );\n },\n accept: async (\n ctx: ComponentCtx,\n args: { token: string; acceptedByUserId: string },\n ) => {\n const tokenHash = await sha256(args.token);\n const result = await ctx.runMutation(\n config.component.public.inviteAcceptByToken,\n { tokenHash, acceptedByUserId: args.acceptedByUserId },\n );\n return { ok: true as const, ...result };\n },\n },\n list: async (\n ctx: ComponentReadCtx,\n opts?: {\n where?: {\n tokenHash?: string;\n groupId?: string;\n status?: \"pending\" | \"accepted\" | \"revoked\" | \"expired\";\n email?: string;\n invitedByUserId?: string;\n roleId?: string;\n acceptedByUserId?: string;\n };\n limit?: number;\n cursor?: string | null;\n orderBy?:\n | \"_creationTime\"\n | \"status\"\n | \"email\"\n | \"expiresTime\"\n | \"acceptedTime\";\n order?: \"asc\" | \"desc\";\n },\n ) => {\n return await ctx.runQuery(config.component.public.inviteList, {\n where: opts?.where,\n limit: opts?.limit,\n cursor: opts?.cursor,\n orderBy: opts?.orderBy,\n order: opts?.order,\n });\n },\n accept: async (\n ctx: ComponentCtx,\n inviteId: string,\n acceptedByUserId?: string,\n ) => {\n await ctx.runMutation(config.component.public.inviteAccept, {\n inviteId,\n ...(acceptedByUserId ? { acceptedByUserId } : {}),\n });\n return {\n ok: true as const,\n inviteId,\n acceptedByUserId: acceptedByUserId ?? null,\n };\n },\n revoke: async (ctx: ComponentCtx, inviteId: string) => {\n await ctx.runMutation(config.component.public.inviteRevoke, { inviteId });\n return { ok: true as const, inviteId };\n },\n };\n\n const key = {\n create: async (\n ctx: ComponentCtx,\n opts: {\n userId: string;\n name: string;\n scopes: KeyScope[];\n rateLimit?: { maxRequests: number; windowMs: number };\n expiresAt?: number;\n metadata?: Record<string, unknown>;\n },\n ): Promise<{ ok: true; keyId: string; secret: string }> => {\n const { raw, hashedKey, displayPrefix } = await generateApiKey(\"sk_\");\n const keyId = (await ctx.runMutation(config.component.public.keyInsert, {\n userId: opts.userId,\n prefix: displayPrefix,\n hashedKey,\n name: opts.name,\n scopes: opts.scopes,\n rateLimit: opts.rateLimit,\n expiresAt: opts.expiresAt,\n metadata: opts.metadata,\n })) as string;\n return { ok: true, keyId, secret: raw };\n },\n verify: async (\n ctx: ComponentCtx,\n rawKey: string,\n ): Promise<\n | { ok: true; userId: string; keyId: string; scopes: ScopeChecker }\n | {\n ok: false;\n code:\n | \"INVALID_API_KEY\"\n | \"API_KEY_REVOKED\"\n | \"API_KEY_EXPIRED\"\n | \"API_KEY_RATE_LIMITED\";\n }\n > => {\n const hashedKey = await hashApiKey(rawKey);\n const doc = (await ctx.runQuery(\n config.component.public.keyGetByHashedKey,\n { hashedKey },\n )) as KeyDoc | null;\n if (!doc) {\n return { ok: false as const, code: \"INVALID_API_KEY\" as const };\n }\n const k = doc;\n if (k.revoked) {\n return { ok: false as const, code: \"API_KEY_REVOKED\" as const };\n }\n if (k.expiresAt && k.expiresAt < Date.now()) {\n return { ok: false as const, code: \"API_KEY_EXPIRED\" as const };\n }\n const patchData: Record<string, unknown> = { lastUsedAt: Date.now() };\n if (k.rateLimit) {\n const { limited, newState } = checkKeyRateLimit(\n k.rateLimit,\n k.rateLimitState ?? undefined,\n );\n if (limited) {\n return { ok: false as const, code: \"API_KEY_RATE_LIMITED\" as const };\n }\n patchData.rateLimitState = newState;\n }\n await ctx.runMutation(config.component.public.keyPatch, {\n keyId: k._id,\n data: patchData,\n });\n return {\n ok: true as const,\n userId: k.userId,\n keyId: k._id,\n scopes: buildScopeChecker(k.scopes),\n };\n },\n list: async (\n ctx: ComponentReadCtx,\n opts?: {\n where?: {\n userId?: string;\n revoked?: boolean;\n name?: string;\n prefix?: string;\n };\n limit?: number;\n cursor?: string | null;\n orderBy?:\n | \"_creationTime\"\n | \"name\"\n | \"lastUsedAt\"\n | \"expiresAt\"\n | \"revoked\";\n order?: \"asc\" | \"desc\";\n },\n ) => {\n return await ctx.runQuery(config.component.public.keyList, {\n where: opts?.where,\n limit: opts?.limit,\n cursor: opts?.cursor,\n orderBy: opts?.orderBy,\n order: opts?.order,\n });\n },\n get: async (\n ctx: ComponentReadCtx,\n keyId: string,\n ): Promise<KeyDoc | null> => {\n return (await ctx.runQuery(config.component.public.keyGetById, {\n keyId,\n })) as KeyDoc | null;\n },\n update: async (\n ctx: ComponentCtx,\n keyId: string,\n data: {\n name?: string;\n scopes?: KeyScope[];\n rateLimit?: { maxRequests: number; windowMs: number };\n },\n ) => {\n await ctx.runMutation(config.component.public.keyPatch, { keyId, data });\n return { ok: true as const, keyId };\n },\n revoke: async (ctx: ComponentCtx, keyId: string) => {\n await ctx.runMutation(config.component.public.keyPatch, {\n keyId,\n data: { revoked: true },\n });\n return { ok: true as const, keyId };\n },\n delete: async (ctx: ComponentCtx, keyId: string) => {\n await ctx.runMutation(config.component.public.keyDelete, { keyId });\n return { ok: true as const, keyId };\n },\n rotate: async (\n ctx: ComponentCtx,\n keyId: string,\n opts?: { name?: string; expiresAt?: number },\n ): Promise<\n | { ok: true; keyId: string; secret: string }\n | { ok: false; code: \"INVALID_PARAMETERS\" | \"API_KEY_REVOKED\" }\n > => {\n const existing = await ctx.runQuery(config.component.public.keyGetById, {\n keyId,\n });\n if (!existing) {\n return { ok: false as const, code: \"INVALID_PARAMETERS\" as const };\n }\n if ((existing as any).revoked === true) {\n return { ok: false as const, code: \"API_KEY_REVOKED\" as const };\n }\n await ctx.runMutation(config.component.public.keyPatch, {\n keyId,\n data: { revoked: true },\n });\n return await key.create(ctx, {\n userId: (existing as any).userId,\n name: opts?.name ?? (existing as any).name,\n scopes: (existing as any).scopes ?? [],\n rateLimit: (existing as any).rateLimit,\n expiresAt: opts?.expiresAt,\n metadata: (existing as any).metadata,\n });\n },\n };\n\n return {\n user,\n session,\n account,\n provider,\n group,\n member,\n access,\n invite,\n key,\n };\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ConvexAuthConfig, Doc, SessionInfo } from "./types.js";
|
|
2
2
|
import * as convex_server25 from "convex/server";
|
|
3
|
-
import * as
|
|
3
|
+
import * as convex_values926 from "convex/values";
|
|
4
4
|
|
|
5
5
|
//#region src/server/factory.d.ts
|
|
6
6
|
/**
|
|
@@ -116,8 +116,8 @@ declare function Auth(config_: ConvexAuthConfig): {
|
|
|
116
116
|
userId: string;
|
|
117
117
|
};
|
|
118
118
|
}, Promise<string | void | {
|
|
119
|
-
userId:
|
|
120
|
-
sessionId:
|
|
119
|
+
userId: convex_values926.GenericId<"User">;
|
|
120
|
+
sessionId: convex_values926.GenericId<"Session">;
|
|
121
121
|
} | (string & {
|
|
122
122
|
__tableName: "AuthVerifier";
|
|
123
123
|
}) | SessionInfo | {
|
|
@@ -55,7 +55,8 @@ function signInFx(ctx, provider, args, options) {
|
|
|
55
55
|
oauth: (p) => handleOAuthProviderFx(ctx, p, args, options),
|
|
56
56
|
passkey: (p) => handlePasskeyFx(ctx, p, args),
|
|
57
57
|
totp: (p) => handleTotp(ctx, p, args),
|
|
58
|
-
device: (p) => handleDevice(ctx, p, args)
|
|
58
|
+
device: (p) => handleDevice(ctx, p, args),
|
|
59
|
+
sso: (_p) => handleSsoProviderFx(ctx, args)
|
|
59
60
|
});
|
|
60
61
|
});
|
|
61
62
|
}
|
|
@@ -175,6 +176,24 @@ function handleOAuthProviderFx(ctx, provider, args, options) {
|
|
|
175
176
|
};
|
|
176
177
|
});
|
|
177
178
|
}
|
|
179
|
+
function handleSsoProviderFx(ctx, args) {
|
|
180
|
+
return Fx.gen(function* () {
|
|
181
|
+
const enterpriseId = args.params?.enterpriseId;
|
|
182
|
+
if (!enterpriseId || typeof enterpriseId !== "string") return yield* Fx.fail(new AuthError("SIGN_IN_MISSING_PARAMS", "enterpriseId is required for SSO sign-in."));
|
|
183
|
+
const protocol = args.params?.protocol ?? "oidc";
|
|
184
|
+
if (protocol !== "oidc" && protocol !== "saml") return yield* Fx.fail(new AuthError("SIGN_IN_MISSING_PARAMS", `Invalid SSO protocol: ${protocol}. Expected "oidc" or "saml".`));
|
|
185
|
+
const verifier = yield* Fx.promise(() => callVerifier(ctx));
|
|
186
|
+
const siteUrl = process.env.CUSTOM_AUTH_SITE_URL ?? requireEnv("CONVEX_SITE_URL");
|
|
187
|
+
const redirect = new URL(`${siteUrl}/api/auth/sso/${enterpriseId}/${protocol}/signin`);
|
|
188
|
+
redirect.searchParams.set("code", verifier);
|
|
189
|
+
if (typeof args.params?.redirectTo === "string") redirect.searchParams.set("redirectTo", args.params.redirectTo);
|
|
190
|
+
return {
|
|
191
|
+
kind: "redirect",
|
|
192
|
+
redirect: redirect.toString(),
|
|
193
|
+
verifier
|
|
194
|
+
};
|
|
195
|
+
});
|
|
196
|
+
}
|
|
178
197
|
|
|
179
198
|
//#endregion
|
|
180
199
|
export { signInImpl };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"signin.js","names":[],"sources":["../../../src/server/signin.ts"],"sourcesContent":["import type { Fx as FxType } from \"@robelest/fx\";\nimport { GenericId } from \"convex/values\";\n\nimport { handleDevice } from \"./device\";\nimport { AuthError, Fx } from \"./fx\";\nimport {\n callCreateVerificationCode,\n callRefreshSession,\n callSignIn,\n callVerifier,\n callVerifierSignature,\n callVerifyCodeAndSignIn,\n} from \"./mutations/index\";\nimport { handlePasskeyFx } from \"./passkey\";\nimport { redirectAbsoluteUrl, setURLSearchParam } from \"./redirects\";\nimport { handleTotp } from \"./totp\";\nimport {\n AuthProviderMaterializedConfig,\n ConvexCredentialsConfig,\n EmailConfig,\n GenericActionCtxWithAuthConfig,\n PhoneConfig,\n} from \"./types\";\nimport {\n AuthDataModel,\n SessionInfo,\n SessionInfoWithTokens,\n Tokens,\n queryTotpVerifiedByUserId,\n} from \"./types\";\nimport type { OAuthMaterializedConfig } from \"./types\";\nimport { generateRandomString } from \"./utils\";\nimport { requireEnv } from \"./utils\";\n\nconst DEFAULT_EMAIL_VERIFICATION_CODE_DURATION_S = 60 * 60 * 24; // 24 hours\n\ntype EnrichedActionCtx = GenericActionCtxWithAuthConfig<AuthDataModel>;\n\ntype SignInResult =\n | { kind: \"signedIn\"; signedIn: SessionInfo | null }\n | { kind: \"refreshTokens\"; signedIn: { tokens: Tokens } }\n | { kind: \"started\"; started: true }\n | { kind: \"redirect\"; redirect: string; verifier: string }\n | { kind: \"passkeyOptions\"; options: Record<string, any>; verifier: string }\n | { kind: \"totpRequired\"; verifier: string }\n | {\n kind: \"totpSetup\";\n uri: string;\n secret: string;\n verifier: string;\n totpId: string;\n }\n | {\n kind: \"deviceCode\";\n deviceCode: string;\n userCode: string;\n verificationUri: string;\n verificationUriComplete: string;\n expiresIn: number;\n interval: number;\n };\n\n/** @internal */\nexport async function signInImpl(\n ctx: EnrichedActionCtx,\n provider: AuthProviderMaterializedConfig | null,\n args: {\n accountId?: GenericId<\"Account\">;\n params?: Record<string, any>;\n verifier?: string;\n refreshToken?: string;\n calledBy?: string;\n },\n options: {\n generateTokens: boolean;\n allowExtraProviders: boolean;\n },\n): Promise<SignInResult> {\n const fx = signInFx(ctx, provider, args, options);\n return Fx.run(\n fx.pipe(Fx.recover((e) => Fx.fatal((e as AuthError).toConvexError()))),\n );\n}\n\n/**\n * Core sign-in pipeline as an Fx generator.\n *\n * Handles: refresh tokens, verification codes, then dispatches by\n * provider type using a dispatch map (no if-chain).\n */\nfunction signInFx(\n ctx: EnrichedActionCtx,\n provider: AuthProviderMaterializedConfig | null,\n args: {\n accountId?: GenericId<\"Account\">;\n params?: Record<string, any>;\n verifier?: string;\n refreshToken?: string;\n calledBy?: string;\n },\n options: {\n generateTokens: boolean;\n allowExtraProviders: boolean;\n },\n): FxType<SignInResult, AuthError> {\n return Fx.gen(function* () {\n // --- Refresh token (no provider) ---\n if (provider === null && args.refreshToken) {\n const tokens = yield* Fx.promise(() =>\n callRefreshSession(ctx, { refreshToken: args.refreshToken! }),\n );\n if (tokens === null) {\n return { kind: \"signedIn\" as const, signedIn: null };\n }\n return { kind: \"refreshTokens\" as const, signedIn: { tokens } };\n }\n\n // --- Verify code (no provider, code present) ---\n if (provider === null && args.params?.code !== undefined) {\n const result = yield* Fx.promise(() =>\n callVerifyCodeAndSignIn(ctx, {\n params: args.params,\n verifier: args.verifier,\n generateTokens: true,\n allowExtraProviders: options.allowExtraProviders,\n }),\n );\n return { kind: \"signedIn\" as const, signedIn: result };\n }\n\n // --- Provider is required past this point ---\n const resolvedProvider = yield* provider != null\n ? Fx.succeed(provider)\n : Fx.fail(new AuthError(\"SIGN_IN_MISSING_PARAMS\"));\n\n // --- Dispatch by provider type ---\n return yield* Fx.match(resolvedProvider).on(\"type\", {\n email: (p) => handleEmailAndPhoneProviderFx(ctx, p, args, options),\n phone: (p) => handleEmailAndPhoneProviderFx(ctx, p, args, options),\n credentials: (p) => handleCredentialsFx(ctx, p, args, options),\n oauth: (p) => handleOAuthProviderFx(ctx, p, args, options),\n passkey: (p) => handlePasskeyFx(ctx, p, args),\n totp: (p) => handleTotp(ctx, p, args),\n device: (p) => handleDevice(ctx, p, args),\n });\n });\n}\n\n// ============================================================================\n// Email / Phone\n// ============================================================================\n\nfunction handleEmailAndPhoneProviderFx(\n ctx: EnrichedActionCtx,\n provider: EmailConfig | PhoneConfig,\n args: {\n params?: Record<string, any>;\n accountId?: GenericId<\"Account\">;\n },\n options: {\n generateTokens: boolean;\n allowExtraProviders: boolean;\n },\n): FxType<\n | { kind: \"started\"; started: true }\n | { kind: \"signedIn\"; signedIn: SessionInfoWithTokens },\n AuthError\n> {\n return Fx.gen(function* () {\n // --- Code verification path ---\n if (args.params?.code !== undefined) {\n const result = yield* Fx.promise(() =>\n callVerifyCodeAndSignIn(ctx, {\n params: args.params,\n provider: provider.id,\n generateTokens: options.generateTokens,\n allowExtraProviders: options.allowExtraProviders,\n }),\n );\n const verified = yield* result != null\n ? Fx.succeed(result)\n : Fx.fail(new AuthError(\"INVALID_VERIFICATION_CODE\"));\n return {\n kind: \"signedIn\" as const,\n signedIn: verified as SessionInfoWithTokens,\n };\n }\n\n // --- Send verification code path ---\n const alphabet =\n \"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\";\n const code = provider.generateVerificationToken\n ? yield* Fx.from({\n ok: async () => provider.generateVerificationToken!(),\n err: () =>\n new AuthError(\n \"INTERNAL_ERROR\",\n \"Failed to generate verification token\",\n ),\n })\n : generateRandomString(32, alphabet);\n const expirationTime =\n Date.now() +\n (provider.maxAge ?? DEFAULT_EMAIL_VERIFICATION_CODE_DURATION_S) * 1000;\n\n const identifier = yield* Fx.promise(() =>\n callCreateVerificationCode(ctx, {\n provider: provider.id,\n accountId: args.accountId,\n email: args.params?.email,\n phone: args.params?.phone,\n code,\n expirationTime,\n allowExtraProviders: options.allowExtraProviders,\n }),\n );\n const destination = yield* Fx.promise(() =>\n redirectAbsoluteUrl(\n ctx.auth.config,\n (args.params ?? {}) as { redirectTo: unknown },\n ),\n );\n const verificationArgs = {\n identifier,\n url: setURLSearchParam(destination, \"code\", code),\n token: code,\n expires: new Date(expirationTime),\n };\n yield* Fx.match(provider).on(\"type\", {\n email: (p) =>\n Fx.from({\n ok: async () =>\n p.sendVerificationRequest(\n {\n ...verificationArgs,\n provider: p,\n request: new Request(\"http://localhost\"),\n },\n ctx,\n ),\n err: () =>\n new AuthError(\"INTERNAL_ERROR\", \"Failed to send email code\"),\n }),\n phone: (p) =>\n Fx.from({\n ok: async () =>\n p.sendVerificationRequest(\n { ...verificationArgs, provider: p },\n ctx,\n ),\n err: () =>\n new AuthError(\"INTERNAL_ERROR\", \"Failed to send phone code\"),\n }),\n });\n return { kind: \"started\" as const, started: true as const };\n });\n}\n\n// ============================================================================\n// Credentials\n// ============================================================================\n\nfunction handleCredentialsFx(\n ctx: EnrichedActionCtx,\n provider: ConvexCredentialsConfig,\n args: {\n params?: Record<string, any>;\n },\n options: {\n generateTokens: boolean;\n },\n): FxType<\n | { kind: \"signedIn\"; signedIn: SessionInfo | null }\n | { kind: \"totpRequired\"; verifier: string },\n AuthError\n> {\n return Fx.gen(function* () {\n const result = yield* Fx.promise(() =>\n provider.authorize(args.params ?? {}, ctx),\n );\n if (result === null) {\n return { kind: \"signedIn\" as const, signedIn: null };\n }\n\n // Check if user has TOTP 2FA enrolled before issuing tokens\n const hasTotpEnrolled = yield* Fx.promise(async () => {\n const totpDoc = await queryTotpVerifiedByUserId(ctx, result.userId);\n return totpDoc !== null;\n });\n if (hasTotpEnrolled) {\n // Create session but withhold tokens — TOTP verification needed\n yield* Fx.promise(() =>\n callSignIn(ctx, {\n userId: result.userId,\n sessionId: result.sessionId,\n generateTokens: false,\n }),\n );\n // Store userId in verifier so the TOTP verify flow can complete sign-in\n const verifier = yield* Fx.promise(() => callVerifier(ctx));\n yield* Fx.promise(() =>\n callVerifierSignature(ctx, {\n verifier,\n signature: JSON.stringify({ userId: result.userId }),\n }),\n );\n return { kind: \"totpRequired\" as const, verifier };\n }\n\n const idsAndTokens = yield* Fx.promise(() =>\n callSignIn(ctx, {\n userId: result.userId,\n sessionId: result.sessionId,\n generateTokens: options.generateTokens,\n }),\n );\n return { kind: \"signedIn\" as const, signedIn: idsAndTokens };\n });\n}\n\n// ============================================================================\n// OAuth\n// ============================================================================\n\nfunction handleOAuthProviderFx(\n ctx: EnrichedActionCtx,\n provider: OAuthMaterializedConfig,\n args: {\n params?: Record<string, any>;\n verifier?: string;\n },\n options: {\n allowExtraProviders: boolean;\n },\n): FxType<\n | { kind: \"signedIn\"; signedIn: SessionInfoWithTokens | null }\n | { kind: \"redirect\"; redirect: string; verifier: string },\n AuthError\n> {\n return Fx.gen(function* () {\n // --- Code verification path ---\n if (args.params?.code !== undefined) {\n const result = yield* Fx.promise(() =>\n callVerifyCodeAndSignIn(ctx, {\n params: args.params,\n verifier: args.verifier,\n generateTokens: true,\n allowExtraProviders: options.allowExtraProviders,\n }),\n );\n return {\n kind: \"signedIn\" as const,\n signedIn: result as SessionInfoWithTokens | null,\n };\n }\n\n // --- Build redirect URL ---\n const redirect = new URL(\n (process.env.CUSTOM_AUTH_SITE_URL ?? requireEnv(\"CONVEX_SITE_URL\")) +\n `/api/auth/signin/${provider.id}`,\n );\n const verifier = yield* Fx.promise(() => callVerifier(ctx));\n redirect.searchParams.set(\"code\", verifier);\n\n if (args.params?.redirectTo !== undefined) {\n yield* Fx.guard(\n typeof args.params.redirectTo !== \"string\",\n Fx.fail(\n new AuthError(\n \"INVALID_REDIRECT\",\n `Expected \\`redirectTo\\` to be a string, got ${args.params.redirectTo}`,\n ),\n ),\n );\n redirect.searchParams.set(\"redirectTo\", args.params.redirectTo);\n }\n\n return {\n kind: \"redirect\" as const,\n redirect: redirect.toString(),\n verifier,\n };\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"signin.js","names":[],"sources":["../../../src/server/signin.ts"],"sourcesContent":["import type { Fx as FxType } from \"@robelest/fx\";\nimport { GenericId } from \"convex/values\";\n\nimport { handleDevice } from \"./device\";\nimport { AuthError, Fx } from \"./fx\";\nimport {\n callCreateVerificationCode,\n callRefreshSession,\n callSignIn,\n callVerifier,\n callVerifierSignature,\n callVerifyCodeAndSignIn,\n} from \"./mutations/index\";\nimport { handlePasskeyFx } from \"./passkey\";\nimport { redirectAbsoluteUrl, setURLSearchParam } from \"./redirects\";\nimport { handleTotp } from \"./totp\";\nimport {\n AuthProviderMaterializedConfig,\n ConvexCredentialsConfig,\n EmailConfig,\n GenericActionCtxWithAuthConfig,\n PhoneConfig,\n} from \"./types\";\nimport {\n AuthDataModel,\n SessionInfo,\n SessionInfoWithTokens,\n Tokens,\n queryTotpVerifiedByUserId,\n} from \"./types\";\nimport type { OAuthMaterializedConfig } from \"./types\";\nimport { generateRandomString } from \"./utils\";\nimport { requireEnv } from \"./utils\";\n\nconst DEFAULT_EMAIL_VERIFICATION_CODE_DURATION_S = 60 * 60 * 24; // 24 hours\n\ntype EnrichedActionCtx = GenericActionCtxWithAuthConfig<AuthDataModel>;\n\ntype SignInResult =\n | { kind: \"signedIn\"; signedIn: SessionInfo | null }\n | { kind: \"refreshTokens\"; signedIn: { tokens: Tokens } }\n | { kind: \"started\"; started: true }\n | { kind: \"redirect\"; redirect: string; verifier: string }\n | { kind: \"passkeyOptions\"; options: Record<string, any>; verifier: string }\n | { kind: \"totpRequired\"; verifier: string }\n | {\n kind: \"totpSetup\";\n uri: string;\n secret: string;\n verifier: string;\n totpId: string;\n }\n | {\n kind: \"deviceCode\";\n deviceCode: string;\n userCode: string;\n verificationUri: string;\n verificationUriComplete: string;\n expiresIn: number;\n interval: number;\n };\n\n/** @internal */\nexport async function signInImpl(\n ctx: EnrichedActionCtx,\n provider: AuthProviderMaterializedConfig | null,\n args: {\n accountId?: GenericId<\"Account\">;\n params?: Record<string, any>;\n verifier?: string;\n refreshToken?: string;\n calledBy?: string;\n },\n options: {\n generateTokens: boolean;\n allowExtraProviders: boolean;\n },\n): Promise<SignInResult> {\n const fx = signInFx(ctx, provider, args, options);\n return Fx.run(\n fx.pipe(Fx.recover((e) => Fx.fatal((e as AuthError).toConvexError()))),\n );\n}\n\n/**\n * Core sign-in pipeline as an Fx generator.\n *\n * Handles: refresh tokens, verification codes, then dispatches by\n * provider type using a dispatch map (no if-chain).\n */\nfunction signInFx(\n ctx: EnrichedActionCtx,\n provider: AuthProviderMaterializedConfig | null,\n args: {\n accountId?: GenericId<\"Account\">;\n params?: Record<string, any>;\n verifier?: string;\n refreshToken?: string;\n calledBy?: string;\n },\n options: {\n generateTokens: boolean;\n allowExtraProviders: boolean;\n },\n): FxType<SignInResult, AuthError> {\n return Fx.gen(function* () {\n // --- Refresh token (no provider) ---\n if (provider === null && args.refreshToken) {\n const tokens = yield* Fx.promise(() =>\n callRefreshSession(ctx, { refreshToken: args.refreshToken! }),\n );\n if (tokens === null) {\n return { kind: \"signedIn\" as const, signedIn: null };\n }\n return { kind: \"refreshTokens\" as const, signedIn: { tokens } };\n }\n\n // --- Verify code (no provider, code present) ---\n if (provider === null && args.params?.code !== undefined) {\n const result = yield* Fx.promise(() =>\n callVerifyCodeAndSignIn(ctx, {\n params: args.params,\n verifier: args.verifier,\n generateTokens: true,\n allowExtraProviders: options.allowExtraProviders,\n }),\n );\n return { kind: \"signedIn\" as const, signedIn: result };\n }\n\n // --- Provider is required past this point ---\n const resolvedProvider = yield* provider != null\n ? Fx.succeed(provider)\n : Fx.fail(new AuthError(\"SIGN_IN_MISSING_PARAMS\"));\n\n // --- Dispatch by provider type ---\n return yield* Fx.match(resolvedProvider).on(\"type\", {\n email: (p) => handleEmailAndPhoneProviderFx(ctx, p, args, options),\n phone: (p) => handleEmailAndPhoneProviderFx(ctx, p, args, options),\n credentials: (p) => handleCredentialsFx(ctx, p, args, options),\n oauth: (p) => handleOAuthProviderFx(ctx, p, args, options),\n passkey: (p) => handlePasskeyFx(ctx, p, args),\n totp: (p) => handleTotp(ctx, p, args),\n device: (p) => handleDevice(ctx, p, args),\n sso: (_p) => handleSsoProviderFx(ctx, args),\n });\n });\n}\n\n// ============================================================================\n// Email / Phone\n// ============================================================================\n\nfunction handleEmailAndPhoneProviderFx(\n ctx: EnrichedActionCtx,\n provider: EmailConfig | PhoneConfig,\n args: {\n params?: Record<string, any>;\n accountId?: GenericId<\"Account\">;\n },\n options: {\n generateTokens: boolean;\n allowExtraProviders: boolean;\n },\n): FxType<\n | { kind: \"started\"; started: true }\n | { kind: \"signedIn\"; signedIn: SessionInfoWithTokens },\n AuthError\n> {\n return Fx.gen(function* () {\n // --- Code verification path ---\n if (args.params?.code !== undefined) {\n const result = yield* Fx.promise(() =>\n callVerifyCodeAndSignIn(ctx, {\n params: args.params,\n provider: provider.id,\n generateTokens: options.generateTokens,\n allowExtraProviders: options.allowExtraProviders,\n }),\n );\n const verified = yield* result != null\n ? Fx.succeed(result)\n : Fx.fail(new AuthError(\"INVALID_VERIFICATION_CODE\"));\n return {\n kind: \"signedIn\" as const,\n signedIn: verified as SessionInfoWithTokens,\n };\n }\n\n // --- Send verification code path ---\n const alphabet =\n \"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\";\n const code = provider.generateVerificationToken\n ? yield* Fx.from({\n ok: async () => provider.generateVerificationToken!(),\n err: () =>\n new AuthError(\n \"INTERNAL_ERROR\",\n \"Failed to generate verification token\",\n ),\n })\n : generateRandomString(32, alphabet);\n const expirationTime =\n Date.now() +\n (provider.maxAge ?? DEFAULT_EMAIL_VERIFICATION_CODE_DURATION_S) * 1000;\n\n const identifier = yield* Fx.promise(() =>\n callCreateVerificationCode(ctx, {\n provider: provider.id,\n accountId: args.accountId,\n email: args.params?.email,\n phone: args.params?.phone,\n code,\n expirationTime,\n allowExtraProviders: options.allowExtraProviders,\n }),\n );\n const destination = yield* Fx.promise(() =>\n redirectAbsoluteUrl(\n ctx.auth.config,\n (args.params ?? {}) as { redirectTo: unknown },\n ),\n );\n const verificationArgs = {\n identifier,\n url: setURLSearchParam(destination, \"code\", code),\n token: code,\n expires: new Date(expirationTime),\n };\n yield* Fx.match(provider).on(\"type\", {\n email: (p) =>\n Fx.from({\n ok: async () =>\n p.sendVerificationRequest(\n {\n ...verificationArgs,\n provider: p,\n request: new Request(\"http://localhost\"),\n },\n ctx,\n ),\n err: () =>\n new AuthError(\"INTERNAL_ERROR\", \"Failed to send email code\"),\n }),\n phone: (p) =>\n Fx.from({\n ok: async () =>\n p.sendVerificationRequest(\n { ...verificationArgs, provider: p },\n ctx,\n ),\n err: () =>\n new AuthError(\"INTERNAL_ERROR\", \"Failed to send phone code\"),\n }),\n });\n return { kind: \"started\" as const, started: true as const };\n });\n}\n\n// ============================================================================\n// Credentials\n// ============================================================================\n\nfunction handleCredentialsFx(\n ctx: EnrichedActionCtx,\n provider: ConvexCredentialsConfig,\n args: {\n params?: Record<string, any>;\n },\n options: {\n generateTokens: boolean;\n },\n): FxType<\n | { kind: \"signedIn\"; signedIn: SessionInfo | null }\n | { kind: \"totpRequired\"; verifier: string },\n AuthError\n> {\n return Fx.gen(function* () {\n const result = yield* Fx.promise(() =>\n provider.authorize(args.params ?? {}, ctx),\n );\n if (result === null) {\n return { kind: \"signedIn\" as const, signedIn: null };\n }\n\n // Check if user has TOTP 2FA enrolled before issuing tokens\n const hasTotpEnrolled = yield* Fx.promise(async () => {\n const totpDoc = await queryTotpVerifiedByUserId(ctx, result.userId);\n return totpDoc !== null;\n });\n if (hasTotpEnrolled) {\n // Create session but withhold tokens — TOTP verification needed\n yield* Fx.promise(() =>\n callSignIn(ctx, {\n userId: result.userId,\n sessionId: result.sessionId,\n generateTokens: false,\n }),\n );\n // Store userId in verifier so the TOTP verify flow can complete sign-in\n const verifier = yield* Fx.promise(() => callVerifier(ctx));\n yield* Fx.promise(() =>\n callVerifierSignature(ctx, {\n verifier,\n signature: JSON.stringify({ userId: result.userId }),\n }),\n );\n return { kind: \"totpRequired\" as const, verifier };\n }\n\n const idsAndTokens = yield* Fx.promise(() =>\n callSignIn(ctx, {\n userId: result.userId,\n sessionId: result.sessionId,\n generateTokens: options.generateTokens,\n }),\n );\n return { kind: \"signedIn\" as const, signedIn: idsAndTokens };\n });\n}\n\n// ============================================================================\n// OAuth\n// ============================================================================\n\nfunction handleOAuthProviderFx(\n ctx: EnrichedActionCtx,\n provider: OAuthMaterializedConfig,\n args: {\n params?: Record<string, any>;\n verifier?: string;\n },\n options: {\n allowExtraProviders: boolean;\n },\n): FxType<\n | { kind: \"signedIn\"; signedIn: SessionInfoWithTokens | null }\n | { kind: \"redirect\"; redirect: string; verifier: string },\n AuthError\n> {\n return Fx.gen(function* () {\n // --- Code verification path ---\n if (args.params?.code !== undefined) {\n const result = yield* Fx.promise(() =>\n callVerifyCodeAndSignIn(ctx, {\n params: args.params,\n verifier: args.verifier,\n generateTokens: true,\n allowExtraProviders: options.allowExtraProviders,\n }),\n );\n return {\n kind: \"signedIn\" as const,\n signedIn: result as SessionInfoWithTokens | null,\n };\n }\n\n // --- Build redirect URL ---\n const redirect = new URL(\n (process.env.CUSTOM_AUTH_SITE_URL ?? requireEnv(\"CONVEX_SITE_URL\")) +\n `/api/auth/signin/${provider.id}`,\n );\n const verifier = yield* Fx.promise(() => callVerifier(ctx));\n redirect.searchParams.set(\"code\", verifier);\n\n if (args.params?.redirectTo !== undefined) {\n yield* Fx.guard(\n typeof args.params.redirectTo !== \"string\",\n Fx.fail(\n new AuthError(\n \"INVALID_REDIRECT\",\n `Expected \\`redirectTo\\` to be a string, got ${args.params.redirectTo}`,\n ),\n ),\n );\n redirect.searchParams.set(\"redirectTo\", args.params.redirectTo);\n }\n\n return {\n kind: \"redirect\" as const,\n redirect: redirect.toString(),\n verifier,\n };\n });\n}\n\n// ============================================================================\n// SSO (Enterprise OIDC / SAML)\n// ============================================================================\n\nfunction handleSsoProviderFx(\n ctx: EnrichedActionCtx,\n args: {\n params?: Record<string, any>;\n },\n): FxType<{ kind: \"redirect\"; redirect: string; verifier: string }, AuthError> {\n return Fx.gen(function* () {\n const enterpriseId = args.params?.enterpriseId;\n if (!enterpriseId || typeof enterpriseId !== \"string\") {\n return yield* Fx.fail(\n new AuthError(\n \"SIGN_IN_MISSING_PARAMS\",\n \"enterpriseId is required for SSO sign-in.\",\n ),\n );\n }\n\n const protocol: \"oidc\" | \"saml\" = args.params?.protocol ?? \"oidc\";\n if (protocol !== \"oidc\" && protocol !== \"saml\") {\n return yield* Fx.fail(\n new AuthError(\n \"SIGN_IN_MISSING_PARAMS\",\n `Invalid SSO protocol: ${protocol as string}. Expected \"oidc\" or \"saml\".`,\n ),\n );\n }\n\n const verifier = yield* Fx.promise(() => callVerifier(ctx));\n const siteUrl =\n process.env.CUSTOM_AUTH_SITE_URL ?? requireEnv(\"CONVEX_SITE_URL\");\n const redirect = new URL(\n `${siteUrl}/api/auth/sso/${enterpriseId}/${protocol}/signin`,\n );\n redirect.searchParams.set(\"code\", verifier);\n\n if (typeof args.params?.redirectTo === \"string\") {\n redirect.searchParams.set(\"redirectTo\", args.params.redirectTo);\n }\n\n return {\n kind: \"redirect\" as const,\n redirect: redirect.toString(),\n verifier,\n };\n });\n}\n"],"mappings":"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"}
|
package/dist/server/auth.d.ts
CHANGED
|
@@ -10,7 +10,7 @@ import { GenericId } from "convex/values";
|
|
|
10
10
|
* minus `component` (which is passed as the first constructor argument).
|
|
11
11
|
*/
|
|
12
12
|
type AuthConfig = Omit<ConvexAuthConfig, "component">;
|
|
13
|
-
type MemberApiWithAuthorization<TAuthorization extends AuthAuthorizationConfig | undefined> = Omit<ReturnType<typeof Auth$1>["auth"]["member"], "create" | "list" | "update" | "
|
|
13
|
+
type MemberApiWithAuthorization<TAuthorization extends AuthAuthorizationConfig | undefined> = Omit<ReturnType<typeof Auth$1>["auth"]["member"], "create" | "list" | "update" | "resolve"> & {
|
|
14
14
|
create: (ctx: Parameters<ReturnType<typeof Auth$1>["auth"]["member"]["create"]>[0], data: {
|
|
15
15
|
groupId: string;
|
|
16
16
|
userId: string;
|
|
@@ -39,20 +39,13 @@ type MemberApiWithAuthorization<TAuthorization extends AuthAuthorizationConfig |
|
|
|
39
39
|
ok: true;
|
|
40
40
|
memberId: string;
|
|
41
41
|
}>;
|
|
42
|
-
|
|
42
|
+
resolve: (ctx: Parameters<ReturnType<typeof Auth$1>["auth"]["member"]["resolve"]>[0], opts: {
|
|
43
43
|
userId: string;
|
|
44
44
|
groupId: string;
|
|
45
45
|
roleIds?: AuthRoleId<TAuthorization>[];
|
|
46
46
|
grants?: AuthGrant<TAuthorization>[];
|
|
47
47
|
maxDepth?: number;
|
|
48
|
-
}) => ReturnType<ReturnType<typeof Auth$1>["auth"]["member"]["
|
|
49
|
-
require: (ctx: Parameters<ReturnType<typeof Auth$1>["auth"]["member"]["require"]>[0], opts: {
|
|
50
|
-
userId: string;
|
|
51
|
-
groupId: string;
|
|
52
|
-
roleIds?: AuthRoleId<TAuthorization>[];
|
|
53
|
-
grants?: AuthGrant<TAuthorization>[];
|
|
54
|
-
maxDepth?: number;
|
|
55
|
-
}) => ReturnType<ReturnType<typeof Auth$1>["auth"]["member"]["require"]>;
|
|
48
|
+
}) => ReturnType<ReturnType<typeof Auth$1>["auth"]["member"]["resolve"]>;
|
|
56
49
|
};
|
|
57
50
|
type AccessApiWithAuthorization<TAuthorization extends AuthAuthorizationConfig | undefined> = {
|
|
58
51
|
check: (ctx: Parameters<ReturnType<typeof Auth$1>["auth"]["access"]["check"]>[0], opts: {
|
|
@@ -61,12 +54,6 @@ type AccessApiWithAuthorization<TAuthorization extends AuthAuthorizationConfig |
|
|
|
61
54
|
grants: AuthGrant<TAuthorization>[];
|
|
62
55
|
maxDepth?: number;
|
|
63
56
|
}) => ReturnType<ReturnType<typeof Auth$1>["auth"]["access"]["check"]>;
|
|
64
|
-
require: (ctx: Parameters<ReturnType<typeof Auth$1>["auth"]["access"]["require"]>[0], opts: {
|
|
65
|
-
userId: string;
|
|
66
|
-
groupId: string;
|
|
67
|
-
grants: AuthGrant<TAuthorization>[];
|
|
68
|
-
maxDepth?: number;
|
|
69
|
-
}) => ReturnType<ReturnType<typeof Auth$1>["auth"]["access"]["require"]>;
|
|
70
57
|
};
|
|
71
58
|
/** The base auth API surface, without conditional namespaces. */
|
|
72
59
|
type AuthApiBase<TAuthorization extends AuthAuthorizationConfig | undefined = undefined> = {
|
|
@@ -199,14 +186,6 @@ declare function createAuth<P extends AuthProviderConfig[], TAuthorization exten
|
|
|
199
186
|
providers: P;
|
|
200
187
|
authorization?: TAuthorization;
|
|
201
188
|
}): ConvexAuthResult<P, TAuthorization>;
|
|
202
|
-
declare function defineRoles<const TRoles extends Record<string, {
|
|
203
|
-
label?: string;
|
|
204
|
-
grants: readonly string[];
|
|
205
|
-
}>>(roles: TRoles): { [K in keyof TRoles]: {
|
|
206
|
-
id: K & string;
|
|
207
|
-
label?: TRoles[K]["label"];
|
|
208
|
-
grants: Array<TRoles[K]["grants"][number] & string>;
|
|
209
|
-
} };
|
|
210
189
|
type UserDoc = Doc<"User">;
|
|
211
190
|
type AuthCtxConfig<TResolve extends Record<string, unknown> = Record<string, never>> = {
|
|
212
191
|
optional?: boolean;
|
|
@@ -250,5 +229,5 @@ type InferAuth<T extends {
|
|
|
250
229
|
}>;
|
|
251
230
|
}> = Awaited<ReturnType<T["input"]>>["ctx"]["auth"];
|
|
252
231
|
//#endregion
|
|
253
|
-
export { AuthApi, AuthApiBase, AuthConfig, AuthCtx, AuthCtxConfig, ConvexAuthResult, InferAuth, InferClientApi, UserDoc, createAuth
|
|
232
|
+
export { AuthApi, AuthApiBase, AuthConfig, AuthCtx, AuthCtxConfig, ConvexAuthResult, InferAuth, InferClientApi, UserDoc, createAuth };
|
|
254
233
|
//# sourceMappingURL=auth.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.d.ts","names":[],"sources":["../../src/server/auth.ts"],"mappings":";;;;;;;;AAmC6D;;;KAAjD,UAAA,GAAa,IAAA,CAAK,gBAAA;AAAA,KAEzB,0BAAA,wBACoB,uBAAA,gBACrB,IAAA,CACF,UAAA,QAAkB,MAAA;EAGlB,MAAA,GACE,GAAA,EAAK,UAAA,CACH,UAAA,QAAkB,MAAA,mCAEpB,IAAA;IACE,OAAA;IACA,MAAA;IACA,OAAA,GAAU,UAAA,CAAW,cAAA;IACrB,MAAA;IACA,MAAA,GAAS,MAAA;EAAA,MAER,OAAA;IAAU,EAAA;IAAU,QAAA;EAAA;EACzB,IAAA,GACE,GAAA,EAAK,UAAA,CACH,UAAA,QAAkB,MAAA,iCAEpB,IAAA;IACE,KAAA;MACE,OAAA;MACA,MAAA;MACA,MAAA,GAAS,UAAA,CAAW,cAAA;MACpB,MAAA;IAAA;IAEF,KAAA;IACA,MAAA;IACA,OAAA;IACA,KAAA;EAAA,MAEC,UAAA,CAAW,UAAA,QAAkB,MAAA;EAClC,MAAA,GACE,GAAA,EAAK,UAAA,CACH,UAAA,QAAkB,MAAA,mCAEpB,QAAA,UACA,IAAA,EAAM,MAAA;IAA4B,OAAA,GAAU,UAAA,CAAW,cAAA;EAAA,MACpD,OAAA;IAAU,EAAA;IAAU,QAAA;EAAA;EACzB,OAAA,GACE,GAAA,EAAK,UAAA,CACH,UAAA,QAAkB,MAAA,oCAEpB,IAAA;IACE,MAAA;IACA,OAAA;IACA,OAAA,GAAU,UAAA,CAAW,cAAA;IACrB,MAAA,GAAS,SAAA,CAAU,cAAA;IACnB,QAAA;EAAA,MAEC,UAAA,CAAW,UAAA,QAAkB,MAAA;
|
|
1
|
+
{"version":3,"file":"auth.d.ts","names":[],"sources":["../../src/server/auth.ts"],"mappings":"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"}
|
package/dist/server/auth.js
CHANGED
|
@@ -117,13 +117,6 @@ function createAuth(component, config) {
|
|
|
117
117
|
http: authResult.auth.http
|
|
118
118
|
};
|
|
119
119
|
}
|
|
120
|
-
function defineRoles(roles) {
|
|
121
|
-
return Object.fromEntries(Object.entries(roles).map(([id, role]) => [id, {
|
|
122
|
-
id,
|
|
123
|
-
...role.label ? { label: role.label } : {},
|
|
124
|
-
grants: [...role.grants]
|
|
125
|
-
}]));
|
|
126
|
-
}
|
|
127
120
|
function AuthCtx(auth, config) {
|
|
128
121
|
return {
|
|
129
122
|
args: {},
|
|
@@ -132,7 +125,7 @@ function AuthCtx(auth, config) {
|
|
|
132
125
|
const modeDispatch = config?.optional === true ? { mode: "optional" } : { mode: "required" };
|
|
133
126
|
const userContext = await Fx.run(Fx.match(modeDispatch, modeDispatch.mode, {
|
|
134
127
|
optional: async () => {
|
|
135
|
-
const userId = await auth.user.
|
|
128
|
+
const userId = await auth.user.id(ctx);
|
|
136
129
|
if (!userId) return null;
|
|
137
130
|
return {
|
|
138
131
|
userId,
|
|
@@ -140,7 +133,8 @@ function AuthCtx(auth, config) {
|
|
|
140
133
|
};
|
|
141
134
|
},
|
|
142
135
|
required: async () => {
|
|
143
|
-
const userId = await auth.user.
|
|
136
|
+
const userId = await auth.user.id(ctx);
|
|
137
|
+
if (!userId) return null;
|
|
144
138
|
return {
|
|
145
139
|
userId,
|
|
146
140
|
user: await auth.user.get(ctx, userId)
|
|
@@ -170,5 +164,5 @@ function AuthCtx(auth, config) {
|
|
|
170
164
|
}
|
|
171
165
|
|
|
172
166
|
//#endregion
|
|
173
|
-
export { AuthCtx, createAuth
|
|
167
|
+
export { AuthCtx, createAuth };
|
|
174
168
|
//# sourceMappingURL=auth.js.map
|