@augmenting-integrations/auth 8.8.0 → 8.10.0
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/server/invitations.d.ts +14 -4
- package/dist/server/invitations.d.ts.map +1 -1
- package/dist/server/profile-settings.d.ts +56 -0
- package/dist/server/profile-settings.d.ts.map +1 -0
- package/dist/server.cjs +125 -8
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.ts +2 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +119 -8
- package/dist/server.js.map +1 -1
- package/package.json +8 -6
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/server/createAuth.ts","../src/server/jit.ts","../src/server/impersonation.ts","../src/server/handlers.ts","../src/server/settings.ts","../src/server/invitations.ts"],"sourcesContent":["// Auth.js v5 (the package is still distributed as `next-auth`, but treat\n// these as Auth.js v5 internally — docs at https://authjs.dev, NOT\n// next-auth.js.org which is v4 and incompatible).\n//\n// Subdomain ecosystem model:\n// - One Cognito User Pool per tenant.\n// - One Cognito App Client with ONE callback URL at the apex\n// (https://<apex>/api/auth/callback/cognito).\n// - The apex app is the auth broker. Subdomain apps redirect through it.\n// - Session cookie scoped to Domain=.<apex> so every subdomain sees it.\n// - All apps use the same createAuth() invocation; the package derives\n// the right signInPage from appDomain + allowedParentDomain.\n//\n// Provider strategy:\n// - Production: Cognito OIDC. cognito:groups drives session.user.groups.\n// - Dev / preview: Credentials with a role picker, shaped to mirror\n// Cognito's claim payload (same groups, sub, email).\n\nimport NextAuth, {\n type DefaultSession,\n type NextAuthConfig,\n type Session,\n} from \"next-auth\";\nimport Credentials from \"next-auth/providers/credentials\";\nimport Cognito from \"next-auth/providers/cognito\";\nimport type { TenantServerConfig } from \"@augmenting-integrations/platform/server\";\n\n// Session augmentation: `groups` is the Cognito-groups array surfaced from\n// the JWT. `role` lives on the application User row (Prisma), exposed via\n// `useAppUser()` from `@augmenting-integrations/auth/client`. There is one\n// source of role-truth; do not add a session-level `role` field back here.\ndeclare module \"next-auth\" {\n interface Session {\n user: {\n groups: string[];\n } & DefaultSession[\"user\"];\n /**\n * Cognito access token, preserved on the session for spoke-side\n * Cognito user-pool calls (TOTP setup/verify, ChangePassword). Only\n * present after a fresh OAuth login on the apex; absent on cookie-only\n * sessions in spokes that never sat in front of the OAuth dance.\n */\n accessToken?: string;\n }\n interface User {\n groups?: string[];\n }\n}\n\nexport type CreateAuthOptions = {\n /**\n * Full tenant configuration. Provides apex/cookieDomain/parentDomain/\n * appDomain/role + cognito client id + issuer + allowed admin emails.\n * Load via `loadTenantConfig()` from `@augmenting-integrations/platform/server`.\n */\n tenant: TenantServerConfig;\n /** Path prefixes that require an authenticated session. */\n authedRoutePrefixes: string[];\n /**\n * JWT signing secret. Caller fetches from Secrets Manager via\n * `getSecret(tenant.authSecretArn)` and passes the resolved value here.\n * The library doesn't bundle AWS SDK reads itself.\n */\n authSecret: string;\n /**\n * Cognito OAuth client secret. Apex apps only -- spokes never run the\n * OAuth dance. Caller fetches from Secrets Manager via\n * `getSecret(tenant.authCognitoSecretArn)`.\n */\n cognitoClientSecret?: string;\n /**\n * Override the auto-derived sign-in page (rarely needed). Default:\n * apex apps get `/login`; spoke apps get `https://<apex>/login`.\n */\n signInPage?: string;\n /** Override prod/dev detection. Default reads NODE_ENV. */\n isProd?: boolean;\n /**\n * App-level access policy. When set, signed-in users whose Cognito\n * identity groups don't intersect `requiredIdentityGroups` are\n * redirected to `forbiddenPage` (default: the apex /login page with\n * `?error=app_forbidden&app=<slug>`). Sourced from\n * `app.manifest.json#access`.\n *\n * `requiredIdentityGroups: []` means all authenticated users may\n * enter; access enforcement is a no-op (same as omitting `appAccess`\n * entirely). This is NOT product-level authorization; it gates entry\n * to the entire app surface, mirroring the manifest field of the\n * same name.\n */\n appAccess?: {\n requiredIdentityGroups: string[];\n /**\n * Optional override. Default:\n * - apex: \"/login?error=app_forbidden&app=<slug>\"\n * - spoke: \"https://<apex>/login?error=app_forbidden&app=<slug>\"\n */\n forbiddenPage?: string;\n };\n};\n\n// ----- AuthError used by requireGroup -----\n\nexport class AuthError extends Error {\n constructor(public code: \"unauthenticated\" | \"forbidden\") {\n super(code);\n this.name = \"AuthError\";\n }\n}\n\n// ----- Group/authorization helpers -----\n\n/** Returns the user's Cognito groups (always an array, possibly empty). */\nexport function getUserGroups(session: Session | null | undefined): string[] {\n return session?.user?.groups ?? [];\n}\n\n/** Case-insensitive group membership check. */\nexport function hasGroup(session: Session | null | undefined, name: string): boolean {\n if (!session) return false;\n const target = name.toLowerCase();\n return getUserGroups(session).some((g) => g.toLowerCase() === target);\n}\n\n/**\n * Throws AuthError if no session (`unauthenticated`) or if the user is in\n * none of the provided groups (`forbidden`). Pass multiple names to allow\n * any-of.\n */\nexport function requireGroup(\n session: Session | null | undefined,\n ...names: string[]\n): void {\n if (!session) throw new AuthError(\"unauthenticated\");\n if (names.length === 0) return;\n const ok = names.some((n) => hasGroup(session, n));\n if (!ok) throw new AuthError(\"forbidden\");\n}\n\n// ----- Redirect callback factory -----\n\nfunction buildRedirectCallback(parentDomain: string) {\n return ({ url, baseUrl }: { url: string; baseUrl: string }): string => {\n try {\n const target = new URL(url, baseUrl);\n const apex = parentDomain.replace(/^\\./, \"\").toLowerCase();\n const host = target.hostname.toLowerCase();\n const ok = host === apex || host.endsWith(`.${apex}`);\n return ok ? target.toString() : baseUrl;\n } catch {\n return baseUrl;\n }\n };\n}\n\n// ----- Sign-in page auto-derivation -----\n\nfunction deriveSignInPage(args: {\n signInPage: string | undefined;\n appDomain: string;\n apex: string;\n}): string {\n if (args.signInPage) return args.signInPage;\n return args.appDomain === args.apex ? \"/login\" : `https://${args.apex}/login`;\n}\n\n// ----- Main factory -----\n\nexport function createAuth(opts: CreateAuthOptions) {\n const { tenant, authSecret, cognitoClientSecret } = opts;\n const isProd = opts.isProd ?? process.env.NODE_ENV === \"production\";\n const cookieDomain = isProd ? tenant.cookieDomain : undefined;\n\n // Skip runtime assertions when not in a real Lambda environment.\n // Matches loadTenantConfig's skip predicate so the two never disagree.\n const skipAsserts =\n process.env.NEXT_PHASE === \"phase-production-build\" ||\n !process.env.AWS_LAMBDA_FUNCTION_NAME;\n\n if (tenant.role === \"apex\" && !skipAsserts) {\n if (!tenant.cognitoClientId || !tenant.cognitoIssuer) {\n throw new Error(\n \"createAuth: tenant.role='apex' requires cognitoClientId + cognitoIssuer. Check loadTenantConfig() inputs.\",\n );\n }\n if (isProd && !cognitoClientSecret) {\n throw new Error(\n \"createAuth: tenant.role='apex' in production requires cognitoClientSecret. Fetch via getSecret(tenant.authCognitoSecretArn) and pass it in.\",\n );\n }\n }\n\n const signInPage = deriveSignInPage({\n signInPage: opts.signInPage,\n appDomain: tenant.appDomain,\n apex: tenant.apex,\n });\n\n const requiredIdentityGroups = opts.appAccess?.requiredIdentityGroups ?? [];\n const hasAccessPolicy = requiredIdentityGroups.length > 0;\n const forbiddenPage =\n opts.appAccess?.forbiddenPage ??\n (tenant.appDomain === tenant.apex\n ? `/login?error=app_forbidden&app=${encodeURIComponent(tenant.appSlug ?? \"apex\")}`\n : `https://${tenant.apex}/login?error=app_forbidden&app=${encodeURIComponent(tenant.appSlug ?? \"\")}`);\n\n const config: NextAuthConfig = {\n secret: authSecret,\n cookies: cookieDomain\n ? {\n sessionToken: {\n name: \"authjs.session-token\",\n options: {\n domain: cookieDomain,\n sameSite: \"lax\",\n secure: true,\n httpOnly: true,\n path: \"/\",\n },\n },\n }\n : undefined,\n providers: isProd\n ? [\n Cognito({\n clientId: tenant.cognitoClientId,\n clientSecret: cognitoClientSecret,\n issuer: tenant.cognitoIssuer,\n }),\n ]\n : [\n Credentials({\n name: \"Mock role (dev only)\",\n credentials: {\n role: {\n label: \"Role\",\n type: \"text\",\n placeholder: \"any role string\",\n },\n },\n authorize: async (credentials) => {\n const role = credentials?.role as string | undefined;\n if (!role) return null;\n const display = role.charAt(0).toUpperCase() + role.slice(1);\n return {\n id: `mock-${role}`,\n name: `${display} (mock)`,\n email: `${role}@example.local`,\n role,\n groups: [role],\n };\n },\n }),\n ],\n session: { strategy: \"jwt\" },\n callbacks: {\n jwt: ({ token, user, profile, account }) => {\n if (user) {\n token.sub ??= user.id ?? undefined;\n token.email ??= user.email ?? undefined;\n if (!isProd) {\n const u = user as { groups?: string[]; role?: string };\n const groups = u.groups ?? (u.role ? [u.role] : []);\n if (groups.length > 0) {\n (token as Record<string, unknown>)[\"cognito:groups\"] = groups;\n }\n }\n }\n if (isProd && profile) {\n const groups = (profile as Record<string, unknown>)[\"cognito:groups\"];\n if (groups) {\n (token as Record<string, unknown>)[\"cognito:groups\"] = groups;\n }\n }\n // Preserve Cognito access_token from the initial OAuth dance so\n // spoke-side user-pool calls (TOTP setup/verify, ChangePassword)\n // can authenticate as the user.\n if (account?.access_token) {\n (token as Record<string, unknown>)[\"accessToken\"] = account.access_token;\n }\n return token;\n },\n session: ({ session, token }) => {\n const groups =\n ((token as Record<string, unknown>)[\"cognito:groups\"] as\n | string[]\n | undefined) ?? [];\n session.user.groups = groups;\n const accessToken = (token as Record<string, unknown>)[\"accessToken\"];\n if (typeof accessToken === \"string\") {\n session.accessToken = accessToken;\n }\n return session;\n },\n authorized: ({ auth: session, request: { nextUrl } }) => {\n const path = nextUrl.pathname;\n const isAuthedRoute = opts.authedRoutePrefixes.some(\n (prefix) => path === prefix || path.startsWith(`${prefix}/`),\n );\n if (!session && isAuthedRoute) {\n // For subdomain apps signInPage is an absolute URL on the apex\n // broker. Auth.js's default middleware redirect treats\n // pages.signIn as a relative path and prepends the current\n // host, producing malformed Location URLs like\n // https://sub.<apex>/https://<apex>/login. Returning an\n // explicit Response.redirect bypasses that path and sends the\n // user to the apex broker correctly.\n if (signInPage.startsWith(\"http\")) {\n const target = new URL(signInPage);\n target.searchParams.set(\"callbackUrl\", nextUrl.href);\n return Response.redirect(target.toString(), 302);\n }\n return false;\n }\n // App-level access enforcement (signed in, accessing a gated route).\n if (session && isAuthedRoute && hasAccessPolicy) {\n const userGroups = (session.user?.groups ?? []).map((g) => g.toLowerCase());\n const allowed = requiredIdentityGroups.some((g) =>\n userGroups.includes(g.toLowerCase()),\n );\n if (!allowed) {\n const target = forbiddenPage.startsWith(\"http\")\n ? new URL(forbiddenPage)\n : new URL(forbiddenPage, nextUrl.origin);\n return Response.redirect(target.toString(), 302);\n }\n }\n return true;\n },\n redirect: buildRedirectCallback(tenant.parentDomain),\n },\n pages: { signIn: signInPage },\n trustHost: true,\n };\n\n return NextAuth(config);\n}\n\nexport type { NextAuthConfig } from \"next-auth\";\n","import \"server-only\";\n\nimport { cookies } from \"next/headers\";\nimport type { Session } from \"next-auth\";\n\nimport { IMPERSONATE_COOKIE_NAME, verifyImpersonationToken } from \"./impersonation.js\";\n\n// =============================================================================\n// JIT user provisioning factory.\n//\n// Pattern: every authed request hands a session into getOrCreateAppUser() to\n// resolve the DB User row (creating one on first sign-in for that email).\n// The factory pattern lets each spoke configure:\n//\n// - `db`: how to reach Prisma (the library doesn't bundle the client)\n// - `defaultRole`: fallback when Cognito groups + ADMIN_EMAILS don't decide\n// - `computeCreditBalance(role)`: starting credit balance per role\n// - `adminEmails`: CSV of emails auto-promoted to admin on first sign-in\n// - `placeholderPasswordHash`: schema-inherited not-null constraint filler\n//\n// Impersonation short-circuit (runs BEFORE the session-driven lookup): if\n// `__impersonate` cookie is present and verifies against AUTH_SECRET, and the\n// underlying admin still exists with role==='admin', returns the *target* user\n// with `impersonatedBy` set to the admin's stringified id. Orphaned tokens\n// silently fall through to the session user.\n//\n// Invitation auto-accept: if a pending Invitation row exists for this email\n// (accepted_at IS NULL, expires_at > now), the new User inherits the\n// invitation's parent_id and intended_role and the invitation is marked\n// accepted in the same transaction.\n// =============================================================================\n\n/**\n * Minimum contract every spoke User row must satisfy. Spokes can widen this\n * with additional fields (credit_balance, must_change_password, etc.) and the\n * factory will preserve them through the returned `Promise<TUser>`.\n */\nexport type BaseAppUser = {\n id: bigint | string | number;\n email: string;\n name: string;\n role: string;\n parent_id: bigint | string | number | null;\n};\n\n/**\n * Loose typing for the Prisma delegates the factory touches. Each spoke has\n * its own generated client whose actual types are concrete; we use loose\n * shapes here so the factory works with any spoke's schema.\n */\nexport type PrismaLikeUserDelegate<TUser> = {\n findUnique: (args: {\n where: { id?: unknown; email?: string };\n }) => Promise<TUser | null>;\n create: (args: { data: unknown }) => Promise<TUser>;\n};\n\nexport type PrismaLikeInvitationDelegate = {\n findFirst: (args: {\n where: { email: string; accepted_at: null; expires_at: { gt: Date } };\n orderBy?: unknown;\n }) => Promise<{\n id: bigint | string | number;\n intended_role: string;\n parent_id: bigint | string | number | null;\n } | null>;\n update: (args: {\n where: { id: unknown };\n data: { accepted_at: Date; accepted_by_user_id: unknown };\n }) => Promise<unknown>;\n};\n\nexport type PrismaLikeClient<TUser> = {\n user: PrismaLikeUserDelegate<TUser>;\n invitation: PrismaLikeInvitationDelegate;\n $transaction: <T>(\n fn: (tx: {\n user: PrismaLikeUserDelegate<TUser>;\n invitation: PrismaLikeInvitationDelegate;\n }) => Promise<T>,\n ) => Promise<T>;\n};\n\nexport type CreateGetOrCreateAppUserOptions<TUser extends BaseAppUser> = {\n /** Returns the spoke's PrismaClient (lazily). */\n db: () => Promise<PrismaLikeClient<TUser>>;\n /** Fallback role when no admin email + no Cognito groups. */\n defaultRole: string;\n /** Starting credit balance per role. */\n computeCreditBalance: (role: string) => number;\n /** Emails auto-promoted to \"admin\" role on first sign-in (case-insensitive). */\n adminEmails?: string[];\n /**\n * Hash value written to User.password on creation. Schema-inherited\n * not-null constraint; never used to authenticate (Cognito does that).\n * Default: a recognizable placeholder string.\n */\n placeholderPasswordHash?: string;\n /**\n * Extra column values written on creation. Use this for spoke-specific\n * defaults (e.g. is_active: true, must_change_password: false).\n */\n extraCreateFields?: Record<string, unknown>;\n};\n\nexport type AppUserWithImpersonation<TUser extends BaseAppUser> = TUser & {\n /** Stringified admin id when this session is impersonated; absent otherwise. */\n impersonatedBy?: string;\n};\n\nconst DEFAULT_PLACEHOLDER_HASH =\n \"$2y$12$.cognito-managed.never.used-for-login.placeholder\";\n\n/**\n * Build a `getOrCreateAppUser(session)` function configured for this spoke.\n *\n * Returned function is idempotent: subsequent calls with the same email\n * return the existing row. First-time emails are created inside a transaction\n * that also auto-accepts a matching Invitation row if present.\n */\nexport function createGetOrCreateAppUser<TUser extends BaseAppUser>(\n opts: CreateGetOrCreateAppUserOptions<TUser>,\n): (session: Session) => Promise<AppUserWithImpersonation<TUser>> {\n const adminEmailsLower = (opts.adminEmails ?? []).map((s) => s.toLowerCase());\n const placeholder = opts.placeholderPasswordHash ?? DEFAULT_PLACEHOLDER_HASH;\n\n return async function getOrCreateAppUser(\n session: Session,\n ): Promise<AppUserWithImpersonation<TUser>> {\n const email = session.user?.email;\n if (!email) {\n throw new Error(\"getOrCreateAppUser called with a session that has no user.email\");\n }\n\n const db = await opts.db();\n\n // -- Impersonation short-circuit (before the session-driven lookup) --\n try {\n const cookieStore = await cookies();\n const cookie = cookieStore.get(IMPERSONATE_COOKIE_NAME);\n if (cookie?.value) {\n const claims = await verifyImpersonationToken(cookie.value);\n if (claims) {\n const [admin, target] = await Promise.all([\n db.user.findUnique({ where: { id: claims.impersonatedBy } }),\n db.user.findUnique({ where: { id: claims.sub } }),\n ]);\n if (admin && admin.role === \"admin\" && target) {\n return Object.assign(target, {\n impersonatedBy: claims.impersonatedBy,\n });\n }\n // Orphaned/expired admin or target -- fall through silently.\n }\n }\n } catch {\n // No cookie context (called from a non-request scope) -- ignore.\n }\n\n const existing = await db.user.findUnique({ where: { email } });\n if (existing) return existing;\n\n // -- New user provisioning --\n const groups = (session.user as { groups?: string[] }).groups ?? [];\n const fallbackRole = adminEmailsLower.includes(email.toLowerCase())\n ? \"admin\"\n : (groups[0] ?? opts.defaultRole);\n const name = (session.user as { name?: string | null }).name ?? email.split(\"@\")[0]!;\n\n return db.$transaction(async (tx) => {\n const pendingInvite = await tx.invitation.findFirst({\n where: {\n email,\n accepted_at: null,\n expires_at: { gt: new Date() },\n },\n orderBy: { created_at: \"desc\" },\n });\n\n const role = pendingInvite ? pendingInvite.intended_role : fallbackRole;\n const parent_id = pendingInvite ? pendingInvite.parent_id : null;\n\n const created = await tx.user.create({\n data: {\n email,\n name,\n role,\n parent_id,\n password: placeholder,\n credit_balance: opts.computeCreditBalance(role),\n ...(opts.extraCreateFields ?? {}),\n },\n });\n\n if (pendingInvite) {\n await tx.invitation.update({\n where: { id: pendingInvite.id },\n data: {\n accepted_at: new Date(),\n accepted_by_user_id: created.id,\n },\n });\n }\n\n return created;\n });\n };\n}\n","import \"server-only\";\n\nimport { encode, decode } from \"next-auth/jwt\";\nimport { getSecret } from \"@augmenting-integrations/aws/server\";\n\n// =============================================================================\n// Impersonation cookie + JWT helpers.\n//\n// Pattern: an admin issues POST /api/admin/users/:id/impersonate, which mints\n// a short-lived JWT and sets it as the `__impersonate` httpOnly cookie. On\n// every subsequent authed request, getOrCreateAppUser reads the cookie,\n// verifies the JWT against AUTH_SECRET, and -- if valid -- returns the\n// *target* user instead of the session user with `impersonatedBy` set.\n//\n// The cookie does NOT replace the next-auth session cookie. It is read\n// alongside the session. Invalid / expired tokens silently fall through.\n//\n// JWT library: next-auth re-exports @auth/core's `encode` / `decode` (JWE).\n// Salted differently from session tokens so they can't be cross-replayed.\n// =============================================================================\n\nexport const IMPERSONATE_COOKIE_NAME = \"__impersonate\";\nexport const IMPERSONATE_TTL_SECONDS = 3600;\nconst IMPERSONATE_JWT_SALT = \"impersonate.v1\";\n\nexport type ImpersonationClaims = {\n /** Admin user id who started the impersonation (stringified BigInt). */\n impersonatedBy: string;\n /** Target user id being impersonated (stringified BigInt). */\n sub: string;\n /** Issued-at (seconds since epoch). */\n iat: number;\n /** Expiry (seconds since epoch). */\n exp: number;\n};\n\nlet cachedSecret: string | null = null;\n\nasync function getAuthSecret(): Promise<string> {\n if (cachedSecret) return cachedSecret;\n const arn = process.env.AUTH_SECRET_ARN;\n const fromSm = arn ? await getSecret(arn) : null;\n const secret = fromSm ?? process.env.AUTH_SECRET;\n if (!secret) {\n throw new Error(\n \"AUTH_SECRET (or AUTH_SECRET_ARN) must be set to mint/verify impersonation tokens\",\n );\n }\n cachedSecret = secret;\n return secret;\n}\n\nexport async function mintImpersonationToken(args: {\n adminId: bigint | string;\n targetId: bigint | string;\n now?: Date;\n}): Promise<{ token: string; expiresAt: Date }> {\n const secret = await getAuthSecret();\n const nowSec = Math.floor((args.now?.getTime() ?? Date.now()) / 1000);\n const exp = nowSec + IMPERSONATE_TTL_SECONDS;\n const token = await encode({\n secret,\n salt: IMPERSONATE_JWT_SALT,\n maxAge: IMPERSONATE_TTL_SECONDS,\n token: {\n impersonatedBy: String(args.adminId),\n sub: String(args.targetId),\n iat: nowSec,\n exp,\n },\n });\n return { token, expiresAt: new Date(exp * 1000) };\n}\n\nexport async function verifyImpersonationToken(\n token: string,\n): Promise<ImpersonationClaims | null> {\n try {\n const secret = await getAuthSecret();\n const decoded = await decode({\n token,\n secret,\n salt: IMPERSONATE_JWT_SALT,\n });\n if (!decoded) return null;\n const impersonatedBy = decoded[\"impersonatedBy\"];\n const sub = decoded[\"sub\"];\n const iat = decoded[\"iat\"];\n const exp = decoded[\"exp\"];\n if (\n typeof impersonatedBy !== \"string\" ||\n typeof sub !== \"string\" ||\n typeof iat !== \"number\" ||\n typeof exp !== \"number\"\n ) {\n return null;\n }\n if (exp * 1000 < Date.now()) return null;\n return { impersonatedBy, sub, iat, exp };\n } catch {\n return null;\n }\n}\n","import \"server-only\";\nimport { NextResponse } from \"next/server\";\nimport type { Session } from \"next-auth\";\n\nimport {\n IMPERSONATE_COOKIE_NAME,\n IMPERSONATE_TTL_SECONDS,\n mintImpersonationToken,\n} from \"./impersonation.js\";\n\n// =============================================================================\n// Library-owned auth-adjacent route handlers.\n//\n// createMeHandler -> GET /api/auth/me\n// createImpersonateHandlers -> POST/DELETE /api/admin/users/[id]/impersonate\n// createInvitationHandlers -> GET/POST /api/invitations/[token]\n//\n// Each factory takes the spoke's `auth()`, `getDb()`, and (for /me +\n// impersonate) `getOrCreateAppUser()` and returns drop-in route exports.\n//\n// The canonical contract: User row has { id, email, name, role, is_active,\n// credit_balance, impersonatedBy? }; Invitation row has { token, email,\n// intended_role, expires_at, accepted_at, inviter:{ name } }; ActivityLog\n// has { user_id, action, metadata }.\n// =============================================================================\n\n// ----- Shared types -----\n\ntype AnyArgs = Record<string, unknown>;\n\nexport type MeAppUser = {\n id: bigint | string | number;\n email: string;\n name: string;\n role: string;\n is_active: boolean;\n credit_balance: number | bigint | string;\n impersonatedBy?: bigint | string | number | null;\n};\n\nexport type AuthHandlersDb = {\n user: {\n findUnique: (args: AnyArgs) => Promise<{\n id: bigint | string | number;\n name: string;\n email: string;\n role?: string;\n } | null>;\n };\n activityLog: {\n create: (args: AnyArgs) => Promise<unknown>;\n };\n invitation: {\n findUnique: (args: AnyArgs) => Promise<{\n email: string;\n intended_role: string;\n expires_at: Date;\n accepted_at: Date | null;\n inviter: { name: string };\n } | null>;\n };\n};\n\ntype AuthFn = () => Promise<Session | null>;\n\n// ----- /api/auth/me -----\n\nexport type CreateMeHandlerOptions = {\n auth: AuthFn;\n getDb: () => Promise<Pick<AuthHandlersDb, \"user\">>;\n getOrCreateAppUser: (session: Session) => Promise<MeAppUser>;\n};\n\nexport function createMeHandler(opts: CreateMeHandlerOptions) {\n return {\n GET: async () => {\n const session = await opts.auth();\n if (!session?.user) {\n return NextResponse.json(\n { error: \"unauthorized\", code: \"unauthorized\" },\n { status: 401 },\n );\n }\n const me = await opts.getOrCreateAppUser(session);\n let impersonatedBy: { id: string; name: string; email: string } | null = null;\n if (me.impersonatedBy) {\n const db = await opts.getDb();\n const admin = await db.user.findUnique({\n where: { id: BigInt(String(me.impersonatedBy)) },\n select: { id: true, name: true, email: true },\n });\n if (admin) {\n impersonatedBy = {\n id: admin.id.toString(),\n name: admin.name,\n email: admin.email,\n };\n }\n }\n return NextResponse.json({\n user: {\n id: me.id.toString(),\n email: me.email,\n name: me.name,\n role: me.role,\n is_active: me.is_active,\n credit_balance: Number(me.credit_balance),\n },\n impersonatedBy,\n });\n },\n };\n}\n\n// ----- /api/admin/users/[id]/impersonate -----\n\nexport type CreateImpersonateHandlersOptions = {\n auth: AuthFn;\n getDb: () => Promise<AuthHandlersDb>;\n getOrCreateAppUser: (session: Session) => Promise<MeAppUser>;\n /** Roles that may impersonate. Default: [\"admin\"]. */\n adminRoles?: string[];\n};\n\nfunction parseIdParam(idStr: string): bigint | null {\n if (!/^\\d+$/u.test(idStr)) return null;\n try {\n return BigInt(idStr);\n } catch {\n return null;\n }\n}\n\nexport function createImpersonateHandlers(opts: CreateImpersonateHandlersOptions) {\n const adminRoles = opts.adminRoles ?? [\"admin\"];\n const isAdminRole = (role: string) =>\n adminRoles.some((r) => r.toLowerCase() === role.toLowerCase());\n\n return {\n POST: async (\n _request: Request,\n ctx: { params: Promise<{ id: string }> },\n ): Promise<Response> => {\n const session = await opts.auth();\n if (!session?.user) {\n return NextResponse.json(\n { error: \"unauthorized\", code: \"unauthorized\" },\n { status: 401 },\n );\n }\n const caller = await opts.getOrCreateAppUser(session);\n if (!isAdminRole(caller.role) || caller.impersonatedBy) {\n return NextResponse.json(\n { error: \"forbidden\", code: \"forbidden\" },\n { status: 403 },\n );\n }\n const { id } = await ctx.params;\n const targetId = parseIdParam(id);\n if (targetId === null) {\n return NextResponse.json(\n { error: \"invalid id\", code: \"validation\" },\n { status: 400 },\n );\n }\n if (targetId === BigInt(String(caller.id))) {\n return NextResponse.json(\n { error: \"cannot impersonate self\", code: \"validation\" },\n { status: 400 },\n );\n }\n const db = await opts.getDb();\n const target = await db.user.findUnique({\n where: { id: targetId },\n select: { id: true, role: true, email: true, name: true },\n });\n if (!target) {\n return NextResponse.json(\n { error: \"not_found\", code: \"not_found\" },\n { status: 404 },\n );\n }\n if (target.role && isAdminRole(target.role)) {\n return NextResponse.json(\n { error: \"cannot impersonate another admin\", code: \"forbidden\" },\n { status: 403 },\n );\n }\n const { token, expiresAt } = await mintImpersonationToken({\n adminId: BigInt(String(caller.id)),\n targetId: BigInt(String(target.id)),\n });\n await db.activityLog.create({\n data: {\n user_id: caller.id,\n action: \"admin.impersonate.start\",\n metadata: {\n target_user_id: target.id.toString(),\n target_email: target.email,\n expires_at: expiresAt.toISOString(),\n },\n },\n });\n const res = NextResponse.json(\n {\n ok: true,\n target: {\n id: target.id.toString(),\n email: target.email,\n name: target.name,\n role: target.role,\n },\n expiresAt: expiresAt.toISOString(),\n },\n { status: 201 },\n );\n res.cookies.set({\n name: IMPERSONATE_COOKIE_NAME,\n value: token,\n httpOnly: true,\n secure: process.env.NODE_ENV === \"production\",\n sameSite: \"lax\",\n path: \"/\",\n maxAge: IMPERSONATE_TTL_SECONDS,\n });\n return res;\n },\n DELETE: async (): Promise<Response> => {\n const session = await opts.auth();\n if (session?.user) {\n try {\n const caller = await opts.getOrCreateAppUser(session);\n if (caller.impersonatedBy) {\n const db = await opts.getDb();\n await db.activityLog.create({\n data: {\n user_id: BigInt(String(caller.impersonatedBy)),\n action: \"admin.impersonate.stop\",\n metadata: { target_user_id: caller.id.toString() },\n },\n });\n }\n } catch {\n // Best-effort audit; never block the stop on logging failure.\n }\n }\n const res = NextResponse.json({ ok: true });\n res.cookies.set({\n name: IMPERSONATE_COOKIE_NAME,\n value: \"\",\n httpOnly: true,\n secure: process.env.NODE_ENV === \"production\",\n sameSite: \"lax\",\n path: \"/\",\n maxAge: 0,\n });\n return res;\n },\n };\n}\n\n// ----- /api/invitations/[token] -----\n\nexport type CreateInvitationHandlersOptions = {\n getDb: () => Promise<Pick<AuthHandlersDb, \"invitation\">>;\n};\n\nexport function createInvitationHandlers(opts: CreateInvitationHandlersOptions) {\n type InvitationPreview = {\n email: string;\n inviter_name: string;\n intended_role: string;\n expires_at: string;\n accepted_at: string | null;\n expired: boolean;\n };\n\n const loadPreview = async (token: string): Promise<InvitationPreview | null> => {\n const db = await opts.getDb();\n const invitation = await db.invitation.findUnique({\n where: { token },\n include: { inviter: { select: { name: true } } },\n });\n if (!invitation) return null;\n return {\n email: invitation.email,\n inviter_name: invitation.inviter.name,\n intended_role: invitation.intended_role,\n expires_at: invitation.expires_at.toISOString(),\n accepted_at: invitation.accepted_at?.toISOString() ?? null,\n expired: invitation.expires_at.getTime() < Date.now(),\n };\n };\n\n const validateToken = (token: string): Response | null => {\n if (!token || token.length > 256) {\n return NextResponse.json(\n { error: \"invalid token\", code: \"validation\" },\n { status: 400 },\n );\n }\n return null;\n };\n\n return {\n GET: async (\n _request: Request,\n { params }: { params: Promise<{ token: string }> },\n ): Promise<Response> => {\n const { token } = await params;\n const invalid = validateToken(token);\n if (invalid) return invalid;\n const preview = await loadPreview(token);\n if (!preview) {\n return NextResponse.json(\n { error: \"invitation not found\", code: \"not_found\" },\n { status: 404 },\n );\n }\n return NextResponse.json(preview);\n },\n POST: async (\n _request: Request,\n { params }: { params: Promise<{ token: string }> },\n ): Promise<Response> => {\n const { token } = await params;\n const invalid = validateToken(token);\n if (invalid) return invalid;\n const preview = await loadPreview(token);\n if (!preview) {\n return NextResponse.json(\n { error: \"invitation not found\", code: \"not_found\" },\n { status: 404 },\n );\n }\n return NextResponse.json({ ok: true, ...preview });\n },\n };\n}\n","import \"server-only\";\nimport { NextResponse } from \"next/server\";\nimport type { Session } from \"next-auth\";\n\n// =============================================================================\n// Library-owned account-settings route handlers.\n//\n// createSettingsHandlers -> { passwordChange, twoFactorSetup,\n// twoFactorVerify, twoFactorDisable }\n//\n// Each entry returns a `{ POST }` shape that drops into the spoke's\n// app/api/settings/* tree as a 2-line re-export. The handlers call into\n// Cognito user-pool APIs to authenticate-as-user via the session's\n// `accessToken`. The library does NOT bundle the Cognito SDK; the spoke\n// passes the SDK calls in via the `cognito` option (they live in\n// @augmenting-integrations/aws/server).\n//\n// The canonical contract: the User row has `must_change_password: boolean`\n// (cleared on password change) and `two_factor_confirmed_at: Date | null`\n// (set/cleared on 2FA enable/disable).\n// =============================================================================\n\ntype AuthFn = () => Promise<Session | null>;\n\nexport type SettingsAppUser = {\n id: bigint | string | number;\n};\n\nexport type SettingsDb = {\n user: {\n update: (args: Record<string, unknown>) => Promise<unknown>;\n };\n};\n\nexport type CognitoOps = {\n associateSoftwareToken: (args: { accessToken: string }) => Promise<{\n secretCode: string;\n }>;\n verifySoftwareToken: (args: { accessToken: string; code: string }) => Promise<{\n status: string;\n }>;\n setUserMfaPreference: (args: {\n accessToken: string;\n enabled: boolean;\n }) => Promise<void>;\n changePassword: (args: {\n accessToken: string;\n previousPassword: string;\n proposedPassword: string;\n }) => Promise<void>;\n buildOtpAuthUri: (args: {\n secret: string;\n accountName: string;\n issuer: string;\n }) => string;\n};\n\nexport type CreateSettingsHandlersOptions = {\n auth: AuthFn;\n getDb: () => Promise<SettingsDb>;\n getOrCreateAppUser: (session: Session) => Promise<SettingsAppUser>;\n cognito: CognitoOps;\n /** OTP issuer name shown in authenticator apps. */\n appDisplayName: string;\n /** Optional QR data URL generator -- spoke supplies `qrcode` if desired. */\n generateQrDataUrl?: (otpAuthUri: string) => Promise<string>;\n};\n\nfunction getAccessToken(session: Session | null): string | null {\n if (!session) return null;\n const fromTop = (session as unknown as { accessToken?: string }).accessToken;\n if (typeof fromTop === \"string\" && fromTop.length > 0) return fromTop;\n return null;\n}\n\nfunction accessTokenMissingResponse() {\n return NextResponse.json(\n {\n error:\n \"Cognito access token not present on the session. The user must sign in fresh on the apex.\",\n code: \"access_token_missing\",\n },\n { status: 401 },\n );\n}\n\nfunction jsonValidation(message: string) {\n return NextResponse.json({ error: message, code: \"validation\" }, { status: 400 });\n}\n\nexport function createSettingsHandlers(opts: CreateSettingsHandlersOptions) {\n // ----- POST /api/settings/password/change -----\n const passwordChange = {\n POST: async (request: Request): Promise<Response> => {\n const session = await opts.auth();\n if (!session?.user) {\n return NextResponse.json({ error: \"unauthorized\" }, { status: 401 });\n }\n const accessToken = getAccessToken(session);\n if (!accessToken) return accessTokenMissingResponse();\n\n let body: { currentPassword?: unknown; newPassword?: unknown };\n try {\n body = (await request.json()) as typeof body;\n } catch {\n return jsonValidation(\"invalid JSON body\");\n }\n const currentPassword =\n typeof body.currentPassword === \"string\" ? body.currentPassword : \"\";\n const newPassword = typeof body.newPassword === \"string\" ? body.newPassword : \"\";\n if (!currentPassword) return jsonValidation(\"currentPassword required\");\n if (newPassword.length < 8)\n return jsonValidation(\"newPassword must be at least 8 chars\");\n\n try {\n await opts.cognito.changePassword({\n accessToken,\n previousPassword: currentPassword,\n proposedPassword: newPassword,\n });\n const appUser = await opts.getOrCreateAppUser(session);\n const db = await opts.getDb();\n await db.user.update({\n where: { id: appUser.id },\n data: { must_change_password: false },\n });\n return NextResponse.json({ ok: true });\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n return NextResponse.json({ error: message, code: \"cognito\" }, { status: 400 });\n }\n },\n };\n\n // ----- POST /api/settings/two-factor/setup -----\n const twoFactorSetup = {\n POST: async (): Promise<Response> => {\n const session = await opts.auth();\n if (!session?.user) {\n return NextResponse.json({ error: \"unauthorized\" }, { status: 401 });\n }\n const accessToken = getAccessToken(session);\n if (!accessToken) return accessTokenMissingResponse();\n try {\n const { secretCode } = await opts.cognito.associateSoftwareToken({\n accessToken,\n });\n const accountName = session.user.email ?? \"user\";\n const otpAuthUri = opts.cognito.buildOtpAuthUri({\n secret: secretCode,\n accountName,\n issuer: opts.appDisplayName,\n });\n const qrDataUrl = opts.generateQrDataUrl\n ? await opts.generateQrDataUrl(otpAuthUri).catch(() => \"\")\n : \"\";\n return NextResponse.json({ qrDataUrl, otpAuthUri, secret: secretCode });\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n return NextResponse.json({ error: message, code: \"cognito\" }, { status: 500 });\n }\n },\n };\n\n // ----- POST /api/settings/two-factor/verify -----\n const twoFactorVerify = {\n POST: async (request: Request): Promise<Response> => {\n const session = await opts.auth();\n if (!session?.user) {\n return NextResponse.json({ error: \"unauthorized\" }, { status: 401 });\n }\n const accessToken = getAccessToken(session);\n if (!accessToken) return accessTokenMissingResponse();\n let body: { code?: unknown };\n try {\n body = (await request.json()) as typeof body;\n } catch {\n return jsonValidation(\"invalid JSON body\");\n }\n const code = typeof body.code === \"string\" ? body.code : \"\";\n if (!/^[0-9]{6}$/.test(code)) return jsonValidation(\"code must be 6 digits\");\n try {\n const result = await opts.cognito.verifySoftwareToken({ accessToken, code });\n if (result.status !== \"SUCCESS\") {\n return NextResponse.json(\n { error: `verify failed: ${result.status}`, code: \"verify_failed\" },\n { status: 400 },\n );\n }\n await opts.cognito.setUserMfaPreference({ accessToken, enabled: true });\n const appUser = await opts.getOrCreateAppUser(session);\n const db = await opts.getDb();\n await db.user.update({\n where: { id: appUser.id },\n data: { two_factor_confirmed_at: new Date() },\n });\n return NextResponse.json({ ok: true });\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n return NextResponse.json({ error: message, code: \"cognito\" }, { status: 500 });\n }\n },\n };\n\n // ----- POST /api/settings/two-factor/disable -----\n const twoFactorDisable = {\n POST: async (): Promise<Response> => {\n const session = await opts.auth();\n if (!session?.user) {\n return NextResponse.json({ error: \"unauthorized\" }, { status: 401 });\n }\n const accessToken = getAccessToken(session);\n if (!accessToken) return accessTokenMissingResponse();\n try {\n await opts.cognito.setUserMfaPreference({ accessToken, enabled: false });\n const appUser = await opts.getOrCreateAppUser(session);\n const db = await opts.getDb();\n await db.user.update({\n where: { id: appUser.id },\n data: { two_factor_confirmed_at: null },\n });\n return NextResponse.json({ ok: true });\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n return NextResponse.json({ error: message, code: \"cognito\" }, { status: 500 });\n }\n },\n };\n\n return { passwordChange, twoFactorSetup, twoFactorVerify, twoFactorDisable };\n}\n","import \"server-only\";\nimport { NextResponse } from \"next/server\";\nimport type { Session } from \"next-auth\";\n\n// =============================================================================\n// Library-owned invitation SEND handler factory.\n//\n// createInvitationSendHandlers -> { send: { POST } }\n//\n// The READ side (preview by token + accept by token) is already library-\n// owned in handlers.ts. This factory covers the canonical send path:\n//\n// 1. Body validation (email, role, optional parent override)\n// 2. Caller role gating via `canInvite` callback\n// 3. Duplicate-user check (refuse to invite an existing user)\n// 4. Invitation row create with token + expiry\n// 5. Email render + send via spoke-provided helpers\n// 6. Response shape (invitationId, expiresAt)\n//\n// Product-specific topology lives in callbacks so the library doesn't\n// hardcode the leads-marketplace hierarchy (`parent_id` from caller's id,\n// admin/agency_owner role set, etc.). The leadsmarket spoke invites a\n// downline; a hypothetical claims-processing spoke might invite peers --\n// the factory accommodates both via `resolveInviteScope`.\n// =============================================================================\n\ntype AuthFn = () => Promise<Session | null>;\n\nexport type InvitationSendAppUser = {\n id: bigint | string | number;\n name: string;\n role: string;\n};\n\nexport type InvitationCreateInput = {\n token: string;\n email: string;\n inviter_id: bigint | string | number;\n intended_role: string;\n parent_id: bigint | string | number | null;\n expires_at: Date;\n};\n\nexport type InvitationCreatedRow = {\n id: bigint | string | number;\n expires_at: Date;\n};\n\nexport type InvitationSendDb = {\n user: {\n findUnique: (args: { where: { email: string } }) => Promise<unknown | null>;\n };\n invitation: {\n create: (args: { data: InvitationCreateInput }) => Promise<InvitationCreatedRow>;\n };\n};\n\nexport type RenderedEmail = {\n subject: string;\n html: string;\n text?: string;\n};\n\nexport type InvitationEmailContext = {\n inviterName: string;\n inviteeEmail: string;\n intendedRole: string;\n invitationUrl: string;\n expiresAt: Date;\n appDisplayName: string;\n};\n\nexport type CreateInvitationSendHandlersOptions = {\n auth: AuthFn;\n getDb: () => Promise<InvitationSendDb>;\n getOrCreateAppUser: (session: Session) => Promise<InvitationSendAppUser>;\n /** Returns true if the caller's role may invite. */\n canInvite: (callerRole: string) => boolean;\n /**\n * Derive the new invitation's parent_id given the caller + the optional\n * client override. Return null for a flat-tree spoke.\n */\n resolveInviteScope: (\n caller: InvitationSendAppUser,\n overrideParentId: bigint | null,\n ) => bigint | string | number | null;\n /** Optional allow-list. If provided, body.role must be one of these. */\n allowedRoles?: string[];\n generateInvitationToken: () => string;\n invitationExpiresAt: () => Date;\n buildInvitationUrl: (token: string, origin: string) => string;\n renderInvitationEmail: (ctx: InvitationEmailContext) => RenderedEmail;\n sendEmail: (args: {\n to: string;\n subject: string;\n html: string;\n text?: string;\n }) => Promise<void>;\n /** Used as fallback origin if APP_DOMAIN env is unset. */\n appDomainEnv?: string;\n /** Issuer name shown in the invitation email. */\n appDisplayName: string;\n};\n\nconst EMAIL_RE = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\nconst ROLE_RE = /^[a-z_]+$/;\nconst PARENT_RE = /^\\d+$/;\n\nfunction jsonError(status: number, error: string, code: string, extra?: object) {\n return NextResponse.json({ error, code, ...(extra ?? {}) }, { status });\n}\n\nexport function createInvitationSendHandlers(opts: CreateInvitationSendHandlersOptions) {\n const send = {\n POST: async (request: Request): Promise<Response> => {\n const session = await opts.auth();\n if (!session?.user) return jsonError(401, \"unauthorized\", \"unauthorized\");\n\n const caller = await opts.getOrCreateAppUser(session);\n if (!opts.canInvite(caller.role)) {\n return jsonError(403, \"forbidden\", \"forbidden\");\n }\n\n let body: { email?: unknown; role?: unknown; parent_id?: unknown };\n try {\n body = (await request.json()) as typeof body;\n } catch {\n return jsonError(400, \"invalid JSON body\", \"validation\");\n }\n const email = typeof body.email === \"string\" ? body.email.trim().toLowerCase() : \"\";\n const role = typeof body.role === \"string\" ? body.role.trim() : \"\";\n const parentIdRaw = body.parent_id;\n if (!EMAIL_RE.test(email) || email.length > 255) {\n return jsonError(400, \"invalid email\", \"validation\");\n }\n if (!role || role.length > 30 || !ROLE_RE.test(role)) {\n return jsonError(400, \"role must be snake_case lowercase\", \"validation\");\n }\n if (opts.allowedRoles && !opts.allowedRoles.includes(role)) {\n return jsonError(\n 400,\n `role must be one of: ${opts.allowedRoles.join(\", \")}`,\n \"validation\",\n );\n }\n let parentOverride: bigint | null = null;\n if (parentIdRaw !== undefined && parentIdRaw !== null) {\n if (typeof parentIdRaw !== \"string\" || !PARENT_RE.test(parentIdRaw)) {\n return jsonError(\n 400,\n \"parent_id must be a stringified BigInt or null\",\n \"validation\",\n );\n }\n parentOverride = BigInt(parentIdRaw);\n }\n\n const parent_id = opts.resolveInviteScope(caller, parentOverride);\n\n const db = await opts.getDb();\n const existing = await db.user.findUnique({ where: { email } });\n if (existing) {\n return jsonError(409, \"user with that email already exists\", \"conflict\");\n }\n\n const token = opts.generateInvitationToken();\n const expiresAt = opts.invitationExpiresAt();\n const invitation = await db.invitation.create({\n data: {\n token,\n email,\n inviter_id: caller.id,\n intended_role: role,\n parent_id,\n expires_at: expiresAt,\n },\n });\n\n const origin = opts.appDomainEnv\n ? `https://${opts.appDomainEnv}`\n : new URL(request.url).origin;\n const invitationUrl = opts.buildInvitationUrl(token, origin);\n const rendered = opts.renderInvitationEmail({\n inviterName: caller.name,\n inviteeEmail: email,\n intendedRole: role,\n invitationUrl,\n expiresAt,\n appDisplayName: opts.appDisplayName,\n });\n\n try {\n await opts.sendEmail({\n to: email,\n subject: rendered.subject,\n html: rendered.html,\n text: rendered.text,\n });\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n return NextResponse.json(\n {\n invitationId: invitation.id.toString(),\n expiresAt: invitation.expires_at.toISOString(),\n warning: `invitation saved but email send failed: ${message}`,\n },\n { status: 202 },\n );\n }\n\n return NextResponse.json(\n {\n invitationId: invitation.id.toString(),\n expiresAt: invitation.expires_at.toISOString(),\n },\n { status: 201 },\n );\n },\n };\n\n return { send };\n}\n"],"mappings":"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","names":["NextResponse","NextResponse"]}
|
|
1
|
+
{"version":3,"sources":["../src/server/createAuth.ts","../src/server/jit.ts","../src/server/impersonation.ts","../src/server/handlers.ts","../src/server/settings.ts","../src/server/profile-settings.ts","../src/server/invitations.ts"],"sourcesContent":["// Auth.js v5 (the package is still distributed as `next-auth`, but treat\n// these as Auth.js v5 internally — docs at https://authjs.dev, NOT\n// next-auth.js.org which is v4 and incompatible).\n//\n// Subdomain ecosystem model:\n// - One Cognito User Pool per tenant.\n// - One Cognito App Client with ONE callback URL at the apex\n// (https://<apex>/api/auth/callback/cognito).\n// - The apex app is the auth broker. Subdomain apps redirect through it.\n// - Session cookie scoped to Domain=.<apex> so every subdomain sees it.\n// - All apps use the same createAuth() invocation; the package derives\n// the right signInPage from appDomain + allowedParentDomain.\n//\n// Provider strategy:\n// - Production: Cognito OIDC. cognito:groups drives session.user.groups.\n// - Dev / preview: Credentials with a role picker, shaped to mirror\n// Cognito's claim payload (same groups, sub, email).\n\nimport NextAuth, {\n type DefaultSession,\n type NextAuthConfig,\n type Session,\n} from \"next-auth\";\nimport Credentials from \"next-auth/providers/credentials\";\nimport Cognito from \"next-auth/providers/cognito\";\nimport type { TenantServerConfig } from \"@augmenting-integrations/platform/server\";\n\n// Session augmentation: `groups` is the Cognito-groups array surfaced from\n// the JWT. `role` lives on the application User row (Prisma), exposed via\n// `useAppUser()` from `@augmenting-integrations/auth/client`. There is one\n// source of role-truth; do not add a session-level `role` field back here.\ndeclare module \"next-auth\" {\n interface Session {\n user: {\n groups: string[];\n } & DefaultSession[\"user\"];\n /**\n * Cognito access token, preserved on the session for spoke-side\n * Cognito user-pool calls (TOTP setup/verify, ChangePassword). Only\n * present after a fresh OAuth login on the apex; absent on cookie-only\n * sessions in spokes that never sat in front of the OAuth dance.\n */\n accessToken?: string;\n }\n interface User {\n groups?: string[];\n }\n}\n\nexport type CreateAuthOptions = {\n /**\n * Full tenant configuration. Provides apex/cookieDomain/parentDomain/\n * appDomain/role + cognito client id + issuer + allowed admin emails.\n * Load via `loadTenantConfig()` from `@augmenting-integrations/platform/server`.\n */\n tenant: TenantServerConfig;\n /** Path prefixes that require an authenticated session. */\n authedRoutePrefixes: string[];\n /**\n * JWT signing secret. Caller fetches from Secrets Manager via\n * `getSecret(tenant.authSecretArn)` and passes the resolved value here.\n * The library doesn't bundle AWS SDK reads itself.\n */\n authSecret: string;\n /**\n * Cognito OAuth client secret. Apex apps only -- spokes never run the\n * OAuth dance. Caller fetches from Secrets Manager via\n * `getSecret(tenant.authCognitoSecretArn)`.\n */\n cognitoClientSecret?: string;\n /**\n * Override the auto-derived sign-in page (rarely needed). Default:\n * apex apps get `/login`; spoke apps get `https://<apex>/login`.\n */\n signInPage?: string;\n /** Override prod/dev detection. Default reads NODE_ENV. */\n isProd?: boolean;\n /**\n * App-level access policy. When set, signed-in users whose Cognito\n * identity groups don't intersect `requiredIdentityGroups` are\n * redirected to `forbiddenPage` (default: the apex /login page with\n * `?error=app_forbidden&app=<slug>`). Sourced from\n * `app.manifest.json#access`.\n *\n * `requiredIdentityGroups: []` means all authenticated users may\n * enter; access enforcement is a no-op (same as omitting `appAccess`\n * entirely). This is NOT product-level authorization; it gates entry\n * to the entire app surface, mirroring the manifest field of the\n * same name.\n */\n appAccess?: {\n requiredIdentityGroups: string[];\n /**\n * Optional override. Default:\n * - apex: \"/login?error=app_forbidden&app=<slug>\"\n * - spoke: \"https://<apex>/login?error=app_forbidden&app=<slug>\"\n */\n forbiddenPage?: string;\n };\n};\n\n// ----- AuthError used by requireGroup -----\n\nexport class AuthError extends Error {\n constructor(public code: \"unauthenticated\" | \"forbidden\") {\n super(code);\n this.name = \"AuthError\";\n }\n}\n\n// ----- Group/authorization helpers -----\n\n/** Returns the user's Cognito groups (always an array, possibly empty). */\nexport function getUserGroups(session: Session | null | undefined): string[] {\n return session?.user?.groups ?? [];\n}\n\n/** Case-insensitive group membership check. */\nexport function hasGroup(session: Session | null | undefined, name: string): boolean {\n if (!session) return false;\n const target = name.toLowerCase();\n return getUserGroups(session).some((g) => g.toLowerCase() === target);\n}\n\n/**\n * Throws AuthError if no session (`unauthenticated`) or if the user is in\n * none of the provided groups (`forbidden`). Pass multiple names to allow\n * any-of.\n */\nexport function requireGroup(\n session: Session | null | undefined,\n ...names: string[]\n): void {\n if (!session) throw new AuthError(\"unauthenticated\");\n if (names.length === 0) return;\n const ok = names.some((n) => hasGroup(session, n));\n if (!ok) throw new AuthError(\"forbidden\");\n}\n\n// ----- Redirect callback factory -----\n\nfunction buildRedirectCallback(parentDomain: string) {\n return ({ url, baseUrl }: { url: string; baseUrl: string }): string => {\n try {\n const target = new URL(url, baseUrl);\n const apex = parentDomain.replace(/^\\./, \"\").toLowerCase();\n const host = target.hostname.toLowerCase();\n const ok = host === apex || host.endsWith(`.${apex}`);\n return ok ? target.toString() : baseUrl;\n } catch {\n return baseUrl;\n }\n };\n}\n\n// ----- Sign-in page auto-derivation -----\n\nfunction deriveSignInPage(args: {\n signInPage: string | undefined;\n appDomain: string;\n apex: string;\n}): string {\n if (args.signInPage) return args.signInPage;\n return args.appDomain === args.apex ? \"/login\" : `https://${args.apex}/login`;\n}\n\n// ----- Main factory -----\n\nexport function createAuth(opts: CreateAuthOptions) {\n const { tenant, authSecret, cognitoClientSecret } = opts;\n const isProd = opts.isProd ?? process.env.NODE_ENV === \"production\";\n const cookieDomain = isProd ? tenant.cookieDomain : undefined;\n\n // Skip runtime assertions when not in a real Lambda environment.\n // Matches loadTenantConfig's skip predicate so the two never disagree.\n const skipAsserts =\n process.env.NEXT_PHASE === \"phase-production-build\" ||\n !process.env.AWS_LAMBDA_FUNCTION_NAME;\n\n if (tenant.role === \"apex\" && !skipAsserts) {\n if (!tenant.cognitoClientId || !tenant.cognitoIssuer) {\n throw new Error(\n \"createAuth: tenant.role='apex' requires cognitoClientId + cognitoIssuer. Check loadTenantConfig() inputs.\",\n );\n }\n if (isProd && !cognitoClientSecret) {\n throw new Error(\n \"createAuth: tenant.role='apex' in production requires cognitoClientSecret. Fetch via getSecret(tenant.authCognitoSecretArn) and pass it in.\",\n );\n }\n }\n\n const signInPage = deriveSignInPage({\n signInPage: opts.signInPage,\n appDomain: tenant.appDomain,\n apex: tenant.apex,\n });\n\n const requiredIdentityGroups = opts.appAccess?.requiredIdentityGroups ?? [];\n const hasAccessPolicy = requiredIdentityGroups.length > 0;\n const forbiddenPage =\n opts.appAccess?.forbiddenPage ??\n (tenant.appDomain === tenant.apex\n ? `/login?error=app_forbidden&app=${encodeURIComponent(tenant.appSlug ?? \"apex\")}`\n : `https://${tenant.apex}/login?error=app_forbidden&app=${encodeURIComponent(tenant.appSlug ?? \"\")}`);\n\n const config: NextAuthConfig = {\n secret: authSecret,\n cookies: cookieDomain\n ? {\n sessionToken: {\n name: \"authjs.session-token\",\n options: {\n domain: cookieDomain,\n sameSite: \"lax\",\n secure: true,\n httpOnly: true,\n path: \"/\",\n },\n },\n }\n : undefined,\n providers: isProd\n ? [\n Cognito({\n clientId: tenant.cognitoClientId,\n clientSecret: cognitoClientSecret,\n issuer: tenant.cognitoIssuer,\n }),\n ]\n : [\n Credentials({\n name: \"Mock role (dev only)\",\n credentials: {\n role: {\n label: \"Role\",\n type: \"text\",\n placeholder: \"any role string\",\n },\n },\n authorize: async (credentials) => {\n const role = credentials?.role as string | undefined;\n if (!role) return null;\n const display = role.charAt(0).toUpperCase() + role.slice(1);\n return {\n id: `mock-${role}`,\n name: `${display} (mock)`,\n email: `${role}@example.local`,\n role,\n groups: [role],\n };\n },\n }),\n ],\n session: { strategy: \"jwt\" },\n callbacks: {\n jwt: ({ token, user, profile, account }) => {\n if (user) {\n token.sub ??= user.id ?? undefined;\n token.email ??= user.email ?? undefined;\n if (!isProd) {\n const u = user as { groups?: string[]; role?: string };\n const groups = u.groups ?? (u.role ? [u.role] : []);\n if (groups.length > 0) {\n (token as Record<string, unknown>)[\"cognito:groups\"] = groups;\n }\n }\n }\n if (isProd && profile) {\n const groups = (profile as Record<string, unknown>)[\"cognito:groups\"];\n if (groups) {\n (token as Record<string, unknown>)[\"cognito:groups\"] = groups;\n }\n }\n // Preserve Cognito access_token from the initial OAuth dance so\n // spoke-side user-pool calls (TOTP setup/verify, ChangePassword)\n // can authenticate as the user.\n if (account?.access_token) {\n (token as Record<string, unknown>)[\"accessToken\"] = account.access_token;\n }\n return token;\n },\n session: ({ session, token }) => {\n const groups =\n ((token as Record<string, unknown>)[\"cognito:groups\"] as\n | string[]\n | undefined) ?? [];\n session.user.groups = groups;\n const accessToken = (token as Record<string, unknown>)[\"accessToken\"];\n if (typeof accessToken === \"string\") {\n session.accessToken = accessToken;\n }\n return session;\n },\n authorized: ({ auth: session, request: { nextUrl } }) => {\n const path = nextUrl.pathname;\n const isAuthedRoute = opts.authedRoutePrefixes.some(\n (prefix) => path === prefix || path.startsWith(`${prefix}/`),\n );\n if (!session && isAuthedRoute) {\n // For subdomain apps signInPage is an absolute URL on the apex\n // broker. Auth.js's default middleware redirect treats\n // pages.signIn as a relative path and prepends the current\n // host, producing malformed Location URLs like\n // https://sub.<apex>/https://<apex>/login. Returning an\n // explicit Response.redirect bypasses that path and sends the\n // user to the apex broker correctly.\n if (signInPage.startsWith(\"http\")) {\n const target = new URL(signInPage);\n target.searchParams.set(\"callbackUrl\", nextUrl.href);\n return Response.redirect(target.toString(), 302);\n }\n return false;\n }\n // App-level access enforcement (signed in, accessing a gated route).\n if (session && isAuthedRoute && hasAccessPolicy) {\n const userGroups = (session.user?.groups ?? []).map((g) => g.toLowerCase());\n const allowed = requiredIdentityGroups.some((g) =>\n userGroups.includes(g.toLowerCase()),\n );\n if (!allowed) {\n const target = forbiddenPage.startsWith(\"http\")\n ? new URL(forbiddenPage)\n : new URL(forbiddenPage, nextUrl.origin);\n return Response.redirect(target.toString(), 302);\n }\n }\n return true;\n },\n redirect: buildRedirectCallback(tenant.parentDomain),\n },\n pages: { signIn: signInPage },\n trustHost: true,\n };\n\n return NextAuth(config);\n}\n\nexport type { NextAuthConfig } from \"next-auth\";\n","import \"server-only\";\n\nimport { cookies } from \"next/headers\";\nimport type { Session } from \"next-auth\";\n\nimport { IMPERSONATE_COOKIE_NAME, verifyImpersonationToken } from \"./impersonation.js\";\n\n// =============================================================================\n// JIT user provisioning factory.\n//\n// Pattern: every authed request hands a session into getOrCreateAppUser() to\n// resolve the DB User row (creating one on first sign-in for that email).\n// The factory pattern lets each spoke configure:\n//\n// - `db`: how to reach Prisma (the library doesn't bundle the client)\n// - `defaultRole`: fallback when Cognito groups + ADMIN_EMAILS don't decide\n// - `computeCreditBalance(role)`: starting credit balance per role\n// - `adminEmails`: CSV of emails auto-promoted to admin on first sign-in\n// - `placeholderPasswordHash`: schema-inherited not-null constraint filler\n//\n// Impersonation short-circuit (runs BEFORE the session-driven lookup): if\n// `__impersonate` cookie is present and verifies against AUTH_SECRET, and the\n// underlying admin still exists with role==='admin', returns the *target* user\n// with `impersonatedBy` set to the admin's stringified id. Orphaned tokens\n// silently fall through to the session user.\n//\n// Invitation auto-accept: if a pending Invitation row exists for this email\n// (accepted_at IS NULL, expires_at > now), the new User inherits the\n// invitation's parent_id and intended_role and the invitation is marked\n// accepted in the same transaction.\n// =============================================================================\n\n/**\n * Minimum contract every spoke User row must satisfy. Spokes can widen this\n * with additional fields (credit_balance, must_change_password, etc.) and the\n * factory will preserve them through the returned `Promise<TUser>`.\n */\nexport type BaseAppUser = {\n id: bigint | string | number;\n email: string;\n name: string;\n role: string;\n parent_id: bigint | string | number | null;\n};\n\n/**\n * Loose typing for the Prisma delegates the factory touches. Each spoke has\n * its own generated client whose actual types are concrete; we use loose\n * shapes here so the factory works with any spoke's schema.\n */\nexport type PrismaLikeUserDelegate<TUser> = {\n findUnique: (args: {\n where: { id?: unknown; email?: string };\n }) => Promise<TUser | null>;\n create: (args: { data: unknown }) => Promise<TUser>;\n};\n\nexport type PrismaLikeInvitationDelegate = {\n findFirst: (args: {\n where: { email: string; accepted_at: null; expires_at: { gt: Date } };\n orderBy?: unknown;\n }) => Promise<{\n id: bigint | string | number;\n intended_role: string;\n parent_id: bigint | string | number | null;\n } | null>;\n update: (args: {\n where: { id: unknown };\n data: { accepted_at: Date; accepted_by_user_id: unknown };\n }) => Promise<unknown>;\n};\n\nexport type PrismaLikeClient<TUser> = {\n user: PrismaLikeUserDelegate<TUser>;\n invitation: PrismaLikeInvitationDelegate;\n $transaction: <T>(\n fn: (tx: {\n user: PrismaLikeUserDelegate<TUser>;\n invitation: PrismaLikeInvitationDelegate;\n }) => Promise<T>,\n ) => Promise<T>;\n};\n\nexport type CreateGetOrCreateAppUserOptions<TUser extends BaseAppUser> = {\n /** Returns the spoke's PrismaClient (lazily). */\n db: () => Promise<PrismaLikeClient<TUser>>;\n /** Fallback role when no admin email + no Cognito groups. */\n defaultRole: string;\n /** Starting credit balance per role. */\n computeCreditBalance: (role: string) => number;\n /** Emails auto-promoted to \"admin\" role on first sign-in (case-insensitive). */\n adminEmails?: string[];\n /**\n * Hash value written to User.password on creation. Schema-inherited\n * not-null constraint; never used to authenticate (Cognito does that).\n * Default: a recognizable placeholder string.\n */\n placeholderPasswordHash?: string;\n /**\n * Extra column values written on creation. Use this for spoke-specific\n * defaults (e.g. is_active: true, must_change_password: false).\n */\n extraCreateFields?: Record<string, unknown>;\n};\n\nexport type AppUserWithImpersonation<TUser extends BaseAppUser> = TUser & {\n /** Stringified admin id when this session is impersonated; absent otherwise. */\n impersonatedBy?: string;\n};\n\nconst DEFAULT_PLACEHOLDER_HASH =\n \"$2y$12$.cognito-managed.never.used-for-login.placeholder\";\n\n/**\n * Build a `getOrCreateAppUser(session)` function configured for this spoke.\n *\n * Returned function is idempotent: subsequent calls with the same email\n * return the existing row. First-time emails are created inside a transaction\n * that also auto-accepts a matching Invitation row if present.\n */\nexport function createGetOrCreateAppUser<TUser extends BaseAppUser>(\n opts: CreateGetOrCreateAppUserOptions<TUser>,\n): (session: Session) => Promise<AppUserWithImpersonation<TUser>> {\n const adminEmailsLower = (opts.adminEmails ?? []).map((s) => s.toLowerCase());\n const placeholder = opts.placeholderPasswordHash ?? DEFAULT_PLACEHOLDER_HASH;\n\n return async function getOrCreateAppUser(\n session: Session,\n ): Promise<AppUserWithImpersonation<TUser>> {\n const email = session.user?.email;\n if (!email) {\n throw new Error(\"getOrCreateAppUser called with a session that has no user.email\");\n }\n\n const db = await opts.db();\n\n // -- Impersonation short-circuit (before the session-driven lookup) --\n try {\n const cookieStore = await cookies();\n const cookie = cookieStore.get(IMPERSONATE_COOKIE_NAME);\n if (cookie?.value) {\n const claims = await verifyImpersonationToken(cookie.value);\n if (claims) {\n const [admin, target] = await Promise.all([\n db.user.findUnique({ where: { id: claims.impersonatedBy } }),\n db.user.findUnique({ where: { id: claims.sub } }),\n ]);\n if (admin && admin.role === \"admin\" && target) {\n return Object.assign(target, {\n impersonatedBy: claims.impersonatedBy,\n });\n }\n // Orphaned/expired admin or target -- fall through silently.\n }\n }\n } catch {\n // No cookie context (called from a non-request scope) -- ignore.\n }\n\n const existing = await db.user.findUnique({ where: { email } });\n if (existing) return existing;\n\n // -- New user provisioning --\n const groups = (session.user as { groups?: string[] }).groups ?? [];\n const fallbackRole = adminEmailsLower.includes(email.toLowerCase())\n ? \"admin\"\n : (groups[0] ?? opts.defaultRole);\n const name = (session.user as { name?: string | null }).name ?? email.split(\"@\")[0]!;\n\n return db.$transaction(async (tx) => {\n const pendingInvite = await tx.invitation.findFirst({\n where: {\n email,\n accepted_at: null,\n expires_at: { gt: new Date() },\n },\n orderBy: { created_at: \"desc\" },\n });\n\n const role = pendingInvite ? pendingInvite.intended_role : fallbackRole;\n const parent_id = pendingInvite ? pendingInvite.parent_id : null;\n\n const created = await tx.user.create({\n data: {\n email,\n name,\n role,\n parent_id,\n password: placeholder,\n credit_balance: opts.computeCreditBalance(role),\n ...(opts.extraCreateFields ?? {}),\n },\n });\n\n if (pendingInvite) {\n await tx.invitation.update({\n where: { id: pendingInvite.id },\n data: {\n accepted_at: new Date(),\n accepted_by_user_id: created.id,\n },\n });\n }\n\n return created;\n });\n };\n}\n","import \"server-only\";\n\nimport { encode, decode } from \"next-auth/jwt\";\nimport { getSecret } from \"@augmenting-integrations/aws/server\";\n\n// =============================================================================\n// Impersonation cookie + JWT helpers.\n//\n// Pattern: an admin issues POST /api/admin/users/:id/impersonate, which mints\n// a short-lived JWT and sets it as the `__impersonate` httpOnly cookie. On\n// every subsequent authed request, getOrCreateAppUser reads the cookie,\n// verifies the JWT against AUTH_SECRET, and -- if valid -- returns the\n// *target* user instead of the session user with `impersonatedBy` set.\n//\n// The cookie does NOT replace the next-auth session cookie. It is read\n// alongside the session. Invalid / expired tokens silently fall through.\n//\n// JWT library: next-auth re-exports @auth/core's `encode` / `decode` (JWE).\n// Salted differently from session tokens so they can't be cross-replayed.\n// =============================================================================\n\nexport const IMPERSONATE_COOKIE_NAME = \"__impersonate\";\nexport const IMPERSONATE_TTL_SECONDS = 3600;\nconst IMPERSONATE_JWT_SALT = \"impersonate.v1\";\n\nexport type ImpersonationClaims = {\n /** Admin user id who started the impersonation (stringified BigInt). */\n impersonatedBy: string;\n /** Target user id being impersonated (stringified BigInt). */\n sub: string;\n /** Issued-at (seconds since epoch). */\n iat: number;\n /** Expiry (seconds since epoch). */\n exp: number;\n};\n\nlet cachedSecret: string | null = null;\n\nasync function getAuthSecret(): Promise<string> {\n if (cachedSecret) return cachedSecret;\n const arn = process.env.AUTH_SECRET_ARN;\n const fromSm = arn ? await getSecret(arn) : null;\n const secret = fromSm ?? process.env.AUTH_SECRET;\n if (!secret) {\n throw new Error(\n \"AUTH_SECRET (or AUTH_SECRET_ARN) must be set to mint/verify impersonation tokens\",\n );\n }\n cachedSecret = secret;\n return secret;\n}\n\nexport async function mintImpersonationToken(args: {\n adminId: bigint | string;\n targetId: bigint | string;\n now?: Date;\n}): Promise<{ token: string; expiresAt: Date }> {\n const secret = await getAuthSecret();\n const nowSec = Math.floor((args.now?.getTime() ?? Date.now()) / 1000);\n const exp = nowSec + IMPERSONATE_TTL_SECONDS;\n const token = await encode({\n secret,\n salt: IMPERSONATE_JWT_SALT,\n maxAge: IMPERSONATE_TTL_SECONDS,\n token: {\n impersonatedBy: String(args.adminId),\n sub: String(args.targetId),\n iat: nowSec,\n exp,\n },\n });\n return { token, expiresAt: new Date(exp * 1000) };\n}\n\nexport async function verifyImpersonationToken(\n token: string,\n): Promise<ImpersonationClaims | null> {\n try {\n const secret = await getAuthSecret();\n const decoded = await decode({\n token,\n secret,\n salt: IMPERSONATE_JWT_SALT,\n });\n if (!decoded) return null;\n const impersonatedBy = decoded[\"impersonatedBy\"];\n const sub = decoded[\"sub\"];\n const iat = decoded[\"iat\"];\n const exp = decoded[\"exp\"];\n if (\n typeof impersonatedBy !== \"string\" ||\n typeof sub !== \"string\" ||\n typeof iat !== \"number\" ||\n typeof exp !== \"number\"\n ) {\n return null;\n }\n if (exp * 1000 < Date.now()) return null;\n return { impersonatedBy, sub, iat, exp };\n } catch {\n return null;\n }\n}\n","import \"server-only\";\nimport { NextResponse } from \"next/server\";\nimport type { Session } from \"next-auth\";\n\nimport {\n IMPERSONATE_COOKIE_NAME,\n IMPERSONATE_TTL_SECONDS,\n mintImpersonationToken,\n} from \"./impersonation.js\";\n\n// =============================================================================\n// Library-owned auth-adjacent route handlers.\n//\n// createMeHandler -> GET /api/auth/me\n// createImpersonateHandlers -> POST/DELETE /api/admin/users/[id]/impersonate\n// createInvitationHandlers -> GET/POST /api/invitations/[token]\n//\n// Each factory takes the spoke's `auth()`, `getDb()`, and (for /me +\n// impersonate) `getOrCreateAppUser()` and returns drop-in route exports.\n//\n// The canonical contract: User row has { id, email, name, role, is_active,\n// credit_balance, impersonatedBy? }; Invitation row has { token, email,\n// intended_role, expires_at, accepted_at, inviter:{ name } }; ActivityLog\n// has { user_id, action, metadata }.\n// =============================================================================\n\n// ----- Shared types -----\n\ntype AnyArgs = Record<string, unknown>;\n\nexport type MeAppUser = {\n id: bigint | string | number;\n email: string;\n name: string;\n role: string;\n is_active: boolean;\n credit_balance: number | bigint | string;\n impersonatedBy?: bigint | string | number | null;\n};\n\nexport type AuthHandlersDb = {\n user: {\n findUnique: (args: AnyArgs) => Promise<{\n id: bigint | string | number;\n name: string;\n email: string;\n role?: string;\n } | null>;\n };\n activityLog: {\n create: (args: AnyArgs) => Promise<unknown>;\n };\n invitation: {\n findUnique: (args: AnyArgs) => Promise<{\n email: string;\n intended_role: string;\n expires_at: Date;\n accepted_at: Date | null;\n inviter: { name: string };\n } | null>;\n };\n};\n\ntype AuthFn = () => Promise<Session | null>;\n\n// ----- /api/auth/me -----\n\nexport type CreateMeHandlerOptions = {\n auth: AuthFn;\n getDb: () => Promise<Pick<AuthHandlersDb, \"user\">>;\n getOrCreateAppUser: (session: Session) => Promise<MeAppUser>;\n};\n\nexport function createMeHandler(opts: CreateMeHandlerOptions) {\n return {\n GET: async () => {\n const session = await opts.auth();\n if (!session?.user) {\n return NextResponse.json(\n { error: \"unauthorized\", code: \"unauthorized\" },\n { status: 401 },\n );\n }\n const me = await opts.getOrCreateAppUser(session);\n let impersonatedBy: { id: string; name: string; email: string } | null = null;\n if (me.impersonatedBy) {\n const db = await opts.getDb();\n const admin = await db.user.findUnique({\n where: { id: BigInt(String(me.impersonatedBy)) },\n select: { id: true, name: true, email: true },\n });\n if (admin) {\n impersonatedBy = {\n id: admin.id.toString(),\n name: admin.name,\n email: admin.email,\n };\n }\n }\n return NextResponse.json({\n user: {\n id: me.id.toString(),\n email: me.email,\n name: me.name,\n role: me.role,\n is_active: me.is_active,\n credit_balance: Number(me.credit_balance),\n },\n impersonatedBy,\n });\n },\n };\n}\n\n// ----- /api/admin/users/[id]/impersonate -----\n\nexport type CreateImpersonateHandlersOptions = {\n auth: AuthFn;\n getDb: () => Promise<AuthHandlersDb>;\n getOrCreateAppUser: (session: Session) => Promise<MeAppUser>;\n /** Roles that may impersonate. Default: [\"admin\"]. */\n adminRoles?: string[];\n};\n\nfunction parseIdParam(idStr: string): bigint | null {\n if (!/^\\d+$/u.test(idStr)) return null;\n try {\n return BigInt(idStr);\n } catch {\n return null;\n }\n}\n\nexport function createImpersonateHandlers(opts: CreateImpersonateHandlersOptions) {\n const adminRoles = opts.adminRoles ?? [\"admin\"];\n const isAdminRole = (role: string) =>\n adminRoles.some((r) => r.toLowerCase() === role.toLowerCase());\n\n return {\n POST: async (\n _request: Request,\n ctx: { params: Promise<{ id: string }> },\n ): Promise<Response> => {\n const session = await opts.auth();\n if (!session?.user) {\n return NextResponse.json(\n { error: \"unauthorized\", code: \"unauthorized\" },\n { status: 401 },\n );\n }\n const caller = await opts.getOrCreateAppUser(session);\n if (!isAdminRole(caller.role) || caller.impersonatedBy) {\n return NextResponse.json(\n { error: \"forbidden\", code: \"forbidden\" },\n { status: 403 },\n );\n }\n const { id } = await ctx.params;\n const targetId = parseIdParam(id);\n if (targetId === null) {\n return NextResponse.json(\n { error: \"invalid id\", code: \"validation\" },\n { status: 400 },\n );\n }\n if (targetId === BigInt(String(caller.id))) {\n return NextResponse.json(\n { error: \"cannot impersonate self\", code: \"validation\" },\n { status: 400 },\n );\n }\n const db = await opts.getDb();\n const target = await db.user.findUnique({\n where: { id: targetId },\n select: { id: true, role: true, email: true, name: true },\n });\n if (!target) {\n return NextResponse.json(\n { error: \"not_found\", code: \"not_found\" },\n { status: 404 },\n );\n }\n if (target.role && isAdminRole(target.role)) {\n return NextResponse.json(\n { error: \"cannot impersonate another admin\", code: \"forbidden\" },\n { status: 403 },\n );\n }\n const { token, expiresAt } = await mintImpersonationToken({\n adminId: BigInt(String(caller.id)),\n targetId: BigInt(String(target.id)),\n });\n await db.activityLog.create({\n data: {\n user_id: caller.id,\n action: \"admin.impersonate.start\",\n metadata: {\n target_user_id: target.id.toString(),\n target_email: target.email,\n expires_at: expiresAt.toISOString(),\n },\n },\n });\n const res = NextResponse.json(\n {\n ok: true,\n target: {\n id: target.id.toString(),\n email: target.email,\n name: target.name,\n role: target.role,\n },\n expiresAt: expiresAt.toISOString(),\n },\n { status: 201 },\n );\n res.cookies.set({\n name: IMPERSONATE_COOKIE_NAME,\n value: token,\n httpOnly: true,\n secure: process.env.NODE_ENV === \"production\",\n sameSite: \"lax\",\n path: \"/\",\n maxAge: IMPERSONATE_TTL_SECONDS,\n });\n return res;\n },\n DELETE: async (): Promise<Response> => {\n const session = await opts.auth();\n if (session?.user) {\n try {\n const caller = await opts.getOrCreateAppUser(session);\n if (caller.impersonatedBy) {\n const db = await opts.getDb();\n await db.activityLog.create({\n data: {\n user_id: BigInt(String(caller.impersonatedBy)),\n action: \"admin.impersonate.stop\",\n metadata: { target_user_id: caller.id.toString() },\n },\n });\n }\n } catch {\n // Best-effort audit; never block the stop on logging failure.\n }\n }\n const res = NextResponse.json({ ok: true });\n res.cookies.set({\n name: IMPERSONATE_COOKIE_NAME,\n value: \"\",\n httpOnly: true,\n secure: process.env.NODE_ENV === \"production\",\n sameSite: \"lax\",\n path: \"/\",\n maxAge: 0,\n });\n return res;\n },\n };\n}\n\n// ----- /api/invitations/[token] -----\n\nexport type CreateInvitationHandlersOptions = {\n getDb: () => Promise<Pick<AuthHandlersDb, \"invitation\">>;\n};\n\nexport function createInvitationHandlers(opts: CreateInvitationHandlersOptions) {\n type InvitationPreview = {\n email: string;\n inviter_name: string;\n intended_role: string;\n expires_at: string;\n accepted_at: string | null;\n expired: boolean;\n };\n\n const loadPreview = async (token: string): Promise<InvitationPreview | null> => {\n const db = await opts.getDb();\n const invitation = await db.invitation.findUnique({\n where: { token },\n include: { inviter: { select: { name: true } } },\n });\n if (!invitation) return null;\n return {\n email: invitation.email,\n inviter_name: invitation.inviter.name,\n intended_role: invitation.intended_role,\n expires_at: invitation.expires_at.toISOString(),\n accepted_at: invitation.accepted_at?.toISOString() ?? null,\n expired: invitation.expires_at.getTime() < Date.now(),\n };\n };\n\n const validateToken = (token: string): Response | null => {\n if (!token || token.length > 256) {\n return NextResponse.json(\n { error: \"invalid token\", code: \"validation\" },\n { status: 400 },\n );\n }\n return null;\n };\n\n return {\n GET: async (\n _request: Request,\n { params }: { params: Promise<{ token: string }> },\n ): Promise<Response> => {\n const { token } = await params;\n const invalid = validateToken(token);\n if (invalid) return invalid;\n const preview = await loadPreview(token);\n if (!preview) {\n return NextResponse.json(\n { error: \"invitation not found\", code: \"not_found\" },\n { status: 404 },\n );\n }\n return NextResponse.json(preview);\n },\n POST: async (\n _request: Request,\n { params }: { params: Promise<{ token: string }> },\n ): Promise<Response> => {\n const { token } = await params;\n const invalid = validateToken(token);\n if (invalid) return invalid;\n const preview = await loadPreview(token);\n if (!preview) {\n return NextResponse.json(\n { error: \"invitation not found\", code: \"not_found\" },\n { status: 404 },\n );\n }\n return NextResponse.json({ ok: true, ...preview });\n },\n };\n}\n","import \"server-only\";\nimport { NextResponse } from \"next/server\";\nimport type { Session } from \"next-auth\";\n\n// =============================================================================\n// Library-owned account-settings route handlers.\n//\n// createSettingsHandlers -> { passwordChange, twoFactorSetup,\n// twoFactorVerify, twoFactorDisable }\n//\n// Each entry returns a `{ POST }` shape that drops into the spoke's\n// app/api/settings/* tree as a 2-line re-export. The handlers call into\n// Cognito user-pool APIs to authenticate-as-user via the session's\n// `accessToken`. The library does NOT bundle the Cognito SDK; the spoke\n// passes the SDK calls in via the `cognito` option (they live in\n// @augmenting-integrations/aws/server).\n//\n// The canonical contract: the User row has `must_change_password: boolean`\n// (cleared on password change) and `two_factor_confirmed_at: Date | null`\n// (set/cleared on 2FA enable/disable).\n// =============================================================================\n\ntype AuthFn = () => Promise<Session | null>;\n\nexport type SettingsAppUser = {\n id: bigint | string | number;\n};\n\nexport type SettingsDb = {\n user: {\n update: (args: Record<string, unknown>) => Promise<unknown>;\n };\n};\n\nexport type CognitoOps = {\n associateSoftwareToken: (args: { accessToken: string }) => Promise<{\n secretCode: string;\n }>;\n verifySoftwareToken: (args: { accessToken: string; code: string }) => Promise<{\n status: string;\n }>;\n setUserMfaPreference: (args: {\n accessToken: string;\n enabled: boolean;\n }) => Promise<void>;\n changePassword: (args: {\n accessToken: string;\n previousPassword: string;\n proposedPassword: string;\n }) => Promise<void>;\n buildOtpAuthUri: (args: {\n secret: string;\n accountName: string;\n issuer: string;\n }) => string;\n};\n\nexport type CreateSettingsHandlersOptions = {\n auth: AuthFn;\n getDb: () => Promise<SettingsDb>;\n getOrCreateAppUser: (session: Session) => Promise<SettingsAppUser>;\n cognito: CognitoOps;\n /** OTP issuer name shown in authenticator apps. */\n appDisplayName: string;\n /** Optional QR data URL generator -- spoke supplies `qrcode` if desired. */\n generateQrDataUrl?: (otpAuthUri: string) => Promise<string>;\n};\n\nfunction getAccessToken(session: Session | null): string | null {\n if (!session) return null;\n const fromTop = (session as unknown as { accessToken?: string }).accessToken;\n if (typeof fromTop === \"string\" && fromTop.length > 0) return fromTop;\n return null;\n}\n\nfunction accessTokenMissingResponse() {\n return NextResponse.json(\n {\n error:\n \"Cognito access token not present on the session. The user must sign in fresh on the apex.\",\n code: \"access_token_missing\",\n },\n { status: 401 },\n );\n}\n\nfunction jsonValidation(message: string) {\n return NextResponse.json({ error: message, code: \"validation\" }, { status: 400 });\n}\n\nexport function createSettingsHandlers(opts: CreateSettingsHandlersOptions) {\n // ----- POST /api/settings/password/change -----\n const passwordChange = {\n POST: async (request: Request): Promise<Response> => {\n const session = await opts.auth();\n if (!session?.user) {\n return NextResponse.json({ error: \"unauthorized\" }, { status: 401 });\n }\n const accessToken = getAccessToken(session);\n if (!accessToken) return accessTokenMissingResponse();\n\n let body: { currentPassword?: unknown; newPassword?: unknown };\n try {\n body = (await request.json()) as typeof body;\n } catch {\n return jsonValidation(\"invalid JSON body\");\n }\n const currentPassword =\n typeof body.currentPassword === \"string\" ? body.currentPassword : \"\";\n const newPassword = typeof body.newPassword === \"string\" ? body.newPassword : \"\";\n if (!currentPassword) return jsonValidation(\"currentPassword required\");\n if (newPassword.length < 8)\n return jsonValidation(\"newPassword must be at least 8 chars\");\n\n try {\n await opts.cognito.changePassword({\n accessToken,\n previousPassword: currentPassword,\n proposedPassword: newPassword,\n });\n const appUser = await opts.getOrCreateAppUser(session);\n const db = await opts.getDb();\n await db.user.update({\n where: { id: appUser.id },\n data: { must_change_password: false },\n });\n return NextResponse.json({ ok: true });\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n return NextResponse.json({ error: message, code: \"cognito\" }, { status: 400 });\n }\n },\n };\n\n // ----- POST /api/settings/two-factor/setup -----\n const twoFactorSetup = {\n POST: async (): Promise<Response> => {\n const session = await opts.auth();\n if (!session?.user) {\n return NextResponse.json({ error: \"unauthorized\" }, { status: 401 });\n }\n const accessToken = getAccessToken(session);\n if (!accessToken) return accessTokenMissingResponse();\n try {\n const { secretCode } = await opts.cognito.associateSoftwareToken({\n accessToken,\n });\n const accountName = session.user.email ?? \"user\";\n const otpAuthUri = opts.cognito.buildOtpAuthUri({\n secret: secretCode,\n accountName,\n issuer: opts.appDisplayName,\n });\n const qrDataUrl = opts.generateQrDataUrl\n ? await opts.generateQrDataUrl(otpAuthUri).catch(() => \"\")\n : \"\";\n return NextResponse.json({ qrDataUrl, otpAuthUri, secret: secretCode });\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n return NextResponse.json({ error: message, code: \"cognito\" }, { status: 500 });\n }\n },\n };\n\n // ----- POST /api/settings/two-factor/verify -----\n const twoFactorVerify = {\n POST: async (request: Request): Promise<Response> => {\n const session = await opts.auth();\n if (!session?.user) {\n return NextResponse.json({ error: \"unauthorized\" }, { status: 401 });\n }\n const accessToken = getAccessToken(session);\n if (!accessToken) return accessTokenMissingResponse();\n let body: { code?: unknown };\n try {\n body = (await request.json()) as typeof body;\n } catch {\n return jsonValidation(\"invalid JSON body\");\n }\n const code = typeof body.code === \"string\" ? body.code : \"\";\n if (!/^[0-9]{6}$/.test(code)) return jsonValidation(\"code must be 6 digits\");\n try {\n const result = await opts.cognito.verifySoftwareToken({ accessToken, code });\n if (result.status !== \"SUCCESS\") {\n return NextResponse.json(\n { error: `verify failed: ${result.status}`, code: \"verify_failed\" },\n { status: 400 },\n );\n }\n await opts.cognito.setUserMfaPreference({ accessToken, enabled: true });\n const appUser = await opts.getOrCreateAppUser(session);\n const db = await opts.getDb();\n await db.user.update({\n where: { id: appUser.id },\n data: { two_factor_confirmed_at: new Date() },\n });\n return NextResponse.json({ ok: true });\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n return NextResponse.json({ error: message, code: \"cognito\" }, { status: 500 });\n }\n },\n };\n\n // ----- POST /api/settings/two-factor/disable -----\n const twoFactorDisable = {\n POST: async (): Promise<Response> => {\n const session = await opts.auth();\n if (!session?.user) {\n return NextResponse.json({ error: \"unauthorized\" }, { status: 401 });\n }\n const accessToken = getAccessToken(session);\n if (!accessToken) return accessTokenMissingResponse();\n try {\n await opts.cognito.setUserMfaPreference({ accessToken, enabled: false });\n const appUser = await opts.getOrCreateAppUser(session);\n const db = await opts.getDb();\n await db.user.update({\n where: { id: appUser.id },\n data: { two_factor_confirmed_at: null },\n });\n return NextResponse.json({ ok: true });\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n return NextResponse.json({ error: message, code: \"cognito\" }, { status: 500 });\n }\n },\n };\n\n return { passwordChange, twoFactorSetup, twoFactorVerify, twoFactorDisable };\n}\n","import \"server-only\";\nimport { NextResponse } from \"next/server\";\nimport type { Session } from \"next-auth\";\nimport type { ZodTypeAny, z } from \"zod\";\n\n// =============================================================================\n// Library-owned profile + account settings route mechanics.\n//\n// createProfileSettingsHandlers -> { profile: { PATCH }, account: { PATCH } }\n//\n// The spoke owns:\n// - which fields each section accepts (Zod schema)\n// - how the parsed payload maps to a Prisma User patch (`toPatch`)\n// - which fields the response echoes back (`select`)\n//\n// The library owns:\n// - auth gate (401)\n// - JSON parse + Zod validation (400 on parse failure or unknown keys)\n// - app-user resolution\n// - db.user.update wiring with the spoke's patch + select\n// - response shape\n// - 500 wrapping for db failures\n//\n// The library makes NO assumption about which User columns exist. Unknown\n// fields are rejected -- spokes should pass a `.strict()` schema so Zod\n// surfaces unknown-key errors as part of the 400 response.\n// =============================================================================\n\ntype AuthFn = () => Promise<Session | null>;\n\nexport type ProfileSettingsAppUser = {\n id: bigint | string | number;\n};\n\nexport type ProfileSettingsDb = {\n user: {\n update: (args: {\n where: { id: bigint | string | number };\n data: Record<string, unknown>;\n select?: Record<string, true>;\n }) => Promise<Record<string, unknown>>;\n };\n};\n\nexport type ProfileSettingsSection = \"profile\" | \"account\";\n\nexport type SectionConfig<TSchema extends ZodTypeAny> = {\n /**\n * Zod schema for the request body. The spoke decides which fields are\n * accepted. Use `.strict()` to reject unknown keys; otherwise Zod will\n * silently strip them and the library cannot enforce that boundary.\n */\n schema: TSchema;\n /**\n * Map the parsed payload to the exact Prisma User patch. The library\n * does NOT infer columns from schema keys; the spoke chooses what gets\n * written. Returning an empty object writes nothing.\n */\n toPatch: (parsed: z.infer<TSchema>) => Record<string, unknown>;\n /** Optional Prisma select shape for the response body. */\n select?: Record<string, true>;\n};\n\nexport type CreateProfileSettingsHandlersOptions<\n TProfileSchema extends ZodTypeAny = ZodTypeAny,\n TAccountSchema extends ZodTypeAny = ZodTypeAny,\n> = {\n auth: AuthFn;\n getDb: () => Promise<ProfileSettingsDb>;\n getOrCreateAppUser: (session: Session) => Promise<ProfileSettingsAppUser>;\n sections: {\n profile: SectionConfig<TProfileSchema>;\n account: SectionConfig<TAccountSchema>;\n };\n /** Invoked once per successful update with the section name + applied patch. */\n afterUpdate?: (\n user: ProfileSettingsAppUser,\n section: ProfileSettingsSection,\n patch: Record<string, unknown>,\n ) => Promise<void>;\n};\n\nfunction unauthorized(): Response {\n return NextResponse.json(\n { error: \"unauthorized\", code: \"unauthorized\" },\n { status: 401 },\n );\n}\n\nfunction jsonValidation(issues: unknown): Response {\n return NextResponse.json({ error: \"invalid_body\", issues }, { status: 400 });\n}\n\nfunction makeHandler<TSchema extends ZodTypeAny>(\n section: ProfileSettingsSection,\n config: SectionConfig<TSchema>,\n opts: CreateProfileSettingsHandlersOptions,\n) {\n return async (request: Request): Promise<Response> => {\n const session = await opts.auth();\n if (!session?.user) return unauthorized();\n\n let body: unknown;\n try {\n body = await request.json();\n } catch {\n return NextResponse.json(\n { error: \"invalid_json\", code: \"validation\" },\n { status: 400 },\n );\n }\n\n const parsed = config.schema.safeParse(body);\n if (!parsed.success) return jsonValidation(parsed.error.issues);\n\n const user = await opts.getOrCreateAppUser(session);\n const patch = config.toPatch(parsed.data);\n const db = await opts.getDb();\n const updated = await db.user.update({\n where: { id: user.id },\n data: patch,\n ...(config.select ? { select: config.select } : {}),\n });\n\n if (opts.afterUpdate) {\n await opts.afterUpdate(user, section, patch);\n }\n\n return NextResponse.json(updated);\n };\n}\n\nexport function createProfileSettingsHandlers<\n TProfileSchema extends ZodTypeAny,\n TAccountSchema extends ZodTypeAny,\n>(opts: CreateProfileSettingsHandlersOptions<TProfileSchema, TAccountSchema>) {\n return {\n profile: { PATCH: makeHandler(\"profile\", opts.sections.profile, opts) },\n account: { PATCH: makeHandler(\"account\", opts.sections.account, opts) },\n };\n}\n","import \"server-only\";\nimport { randomBytes } from \"node:crypto\";\nimport { NextResponse } from \"next/server\";\nimport type { Session } from \"next-auth\";\n\n// =============================================================================\n// Library-owned invitation SEND handler factory.\n//\n// createInvitationSendHandlers -> { send: { POST } }\n//\n// The READ side (preview by token + accept by token) is already library-\n// owned in handlers.ts. This factory covers the canonical send path:\n//\n// 1. Body validation (email, role, optional parent override)\n// 2. Caller role gating via `canInvite` callback\n// 3. Duplicate-user check (refuse to invite an existing user)\n// 4. Invitation row create with token + expiry\n// 5. Email render + send via spoke-provided helpers\n// 6. Response shape (invitationId, expiresAt)\n//\n// Product-specific topology lives in callbacks so the library doesn't\n// hardcode any spoke's role set or `parent_id` derivation. Generic\n// invitation mechanics (token gen, expiry, URL build, email render)\n// ship as defaults; spokes override only when they need different\n// branding or token shape.\n// =============================================================================\n\nexport const INVITATION_TTL_HOURS = 72;\n\n/** 32 random bytes -> base64url, no padding. 256 bits of entropy in 43 chars. */\nexport function defaultGenerateInvitationToken(): string {\n return randomBytes(32).toString(\"base64url\");\n}\n\nexport function defaultInvitationExpiresAt(now: Date = new Date()): Date {\n const expires = new Date(now);\n expires.setHours(expires.getHours() + INVITATION_TTL_HOURS);\n return expires;\n}\n\nexport function defaultBuildInvitationUrl(token: string, origin: string): string {\n // Trim trailing slash so the result is always exactly one slash before /invitations.\n const trimmed = origin.replace(/\\/+$/u, \"\");\n return `${trimmed}/invitations/${token}`;\n}\n\nexport function defaultRenderInvitationEmail(ctx: InvitationEmailContext): RenderedEmail {\n const {\n inviterName,\n inviteeEmail,\n intendedRole,\n invitationUrl,\n appDisplayName,\n expiresAt,\n } = ctx;\n const subject = `${appDisplayName} | You've been invited`;\n const expiresIso = expiresAt.toISOString();\n const html = `<!doctype html>\n<html>\n <body style=\"font-family: system-ui, sans-serif; max-width: 560px; margin: 0 auto; padding: 24px;\">\n <h1 style=\"font-size: 20px; margin: 0 0 16px;\">You've been invited to ${escapeHtml(appDisplayName)}</h1>\n <p>${escapeHtml(inviterName)} invited <strong>${escapeHtml(inviteeEmail)}</strong> to join their team as <strong>${escapeHtml(intendedRole)}</strong>.</p>\n <p>\n <a href=\"${escapeAttr(invitationUrl)}\" style=\"display: inline-block; padding: 10px 16px; background: #111; color: #fff; text-decoration: none; border-radius: 6px;\">Accept invitation</a>\n </p>\n <p style=\"color: #555; font-size: 13px;\">This invitation expires at ${escapeHtml(expiresIso)}. If you didn't expect this, you can ignore this email.</p>\n </body>\n</html>`;\n const text = [\n `You've been invited to ${appDisplayName}`,\n \"\",\n `${inviterName} invited ${inviteeEmail} to join their team as ${intendedRole}.`,\n \"\",\n `Accept the invitation: ${invitationUrl}`,\n \"\",\n `This invitation expires at ${expiresIso}.`,\n ].join(\"\\n\");\n return { subject, html, text };\n}\n\nfunction escapeHtml(s: string): string {\n return s\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\")\n .replace(/'/g, \"'\");\n}\n\nfunction escapeAttr(s: string): string {\n return escapeHtml(s);\n}\n\ntype AuthFn = () => Promise<Session | null>;\n\nexport type InvitationSendAppUser = {\n id: bigint | string | number;\n name: string;\n role: string;\n};\n\nexport type InvitationCreateInput = {\n token: string;\n email: string;\n inviter_id: bigint | string | number;\n intended_role: string;\n parent_id: bigint | string | number | null;\n expires_at: Date;\n};\n\nexport type InvitationCreatedRow = {\n id: bigint | string | number;\n expires_at: Date;\n};\n\nexport type InvitationSendDb = {\n user: {\n findUnique: (args: { where: { email: string } }) => Promise<unknown | null>;\n };\n invitation: {\n create: (args: { data: InvitationCreateInput }) => Promise<InvitationCreatedRow>;\n };\n};\n\nexport type RenderedEmail = {\n subject: string;\n html: string;\n text?: string;\n};\n\nexport type InvitationEmailContext = {\n inviterName: string;\n inviteeEmail: string;\n intendedRole: string;\n invitationUrl: string;\n expiresAt: Date;\n appDisplayName: string;\n};\n\nexport type CreateInvitationSendHandlersOptions = {\n auth: AuthFn;\n getDb: () => Promise<InvitationSendDb>;\n getOrCreateAppUser: (session: Session) => Promise<InvitationSendAppUser>;\n /** Returns true if the caller's role may invite. */\n canInvite: (callerRole: string) => boolean;\n /**\n * Derive the new invitation's parent_id given the caller + the optional\n * client override. Return null for a flat-tree spoke.\n */\n resolveInviteScope: (\n caller: InvitationSendAppUser,\n overrideParentId: bigint | null,\n ) => bigint | string | number | null;\n /** Optional allow-list. If provided, body.role must be one of these. */\n allowedRoles?: string[];\n /** Optional. Defaults to {@link defaultGenerateInvitationToken}. */\n generateInvitationToken?: () => string;\n /** Optional. Defaults to {@link defaultInvitationExpiresAt}. */\n invitationExpiresAt?: () => Date;\n /** Optional. Defaults to {@link defaultBuildInvitationUrl}. */\n buildInvitationUrl?: (token: string, origin: string) => string;\n /** Optional. Defaults to {@link defaultRenderInvitationEmail}. */\n renderInvitationEmail?: (ctx: InvitationEmailContext) => RenderedEmail;\n sendEmail: (args: {\n to: string;\n subject: string;\n html: string;\n text?: string;\n }) => Promise<void>;\n /** Used as fallback origin if APP_DOMAIN env is unset. */\n appDomainEnv?: string;\n /** Issuer name shown in the invitation email. */\n appDisplayName: string;\n};\n\nconst EMAIL_RE = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\nconst ROLE_RE = /^[a-z_]+$/;\nconst PARENT_RE = /^\\d+$/;\n\nfunction jsonError(status: number, error: string, code: string, extra?: object) {\n return NextResponse.json({ error, code, ...(extra ?? {}) }, { status });\n}\n\nexport function createInvitationSendHandlers(opts: CreateInvitationSendHandlersOptions) {\n const generateInvitationToken =\n opts.generateInvitationToken ?? defaultGenerateInvitationToken;\n const invitationExpiresAt = opts.invitationExpiresAt ?? defaultInvitationExpiresAt;\n const buildInvitationUrl = opts.buildInvitationUrl ?? defaultBuildInvitationUrl;\n const renderInvitationEmail =\n opts.renderInvitationEmail ?? defaultRenderInvitationEmail;\n const send = {\n POST: async (request: Request): Promise<Response> => {\n const session = await opts.auth();\n if (!session?.user) return jsonError(401, \"unauthorized\", \"unauthorized\");\n\n const caller = await opts.getOrCreateAppUser(session);\n if (!opts.canInvite(caller.role)) {\n return jsonError(403, \"forbidden\", \"forbidden\");\n }\n\n let body: { email?: unknown; role?: unknown; parent_id?: unknown };\n try {\n body = (await request.json()) as typeof body;\n } catch {\n return jsonError(400, \"invalid JSON body\", \"validation\");\n }\n const email = typeof body.email === \"string\" ? body.email.trim().toLowerCase() : \"\";\n const role = typeof body.role === \"string\" ? body.role.trim() : \"\";\n const parentIdRaw = body.parent_id;\n if (!EMAIL_RE.test(email) || email.length > 255) {\n return jsonError(400, \"invalid email\", \"validation\");\n }\n if (!role || role.length > 30 || !ROLE_RE.test(role)) {\n return jsonError(400, \"role must be snake_case lowercase\", \"validation\");\n }\n if (opts.allowedRoles && !opts.allowedRoles.includes(role)) {\n return jsonError(\n 400,\n `role must be one of: ${opts.allowedRoles.join(\", \")}`,\n \"validation\",\n );\n }\n let parentOverride: bigint | null = null;\n if (parentIdRaw !== undefined && parentIdRaw !== null) {\n if (typeof parentIdRaw !== \"string\" || !PARENT_RE.test(parentIdRaw)) {\n return jsonError(\n 400,\n \"parent_id must be a stringified BigInt or null\",\n \"validation\",\n );\n }\n parentOverride = BigInt(parentIdRaw);\n }\n\n const parent_id = opts.resolveInviteScope(caller, parentOverride);\n\n const db = await opts.getDb();\n const existing = await db.user.findUnique({ where: { email } });\n if (existing) {\n return jsonError(409, \"user with that email already exists\", \"conflict\");\n }\n\n const token = generateInvitationToken();\n const expiresAt = invitationExpiresAt();\n const invitation = await db.invitation.create({\n data: {\n token,\n email,\n inviter_id: caller.id,\n intended_role: role,\n parent_id,\n expires_at: expiresAt,\n },\n });\n\n const origin = opts.appDomainEnv\n ? `https://${opts.appDomainEnv}`\n : new URL(request.url).origin;\n const invitationUrl = buildInvitationUrl(token, origin);\n const rendered = renderInvitationEmail({\n inviterName: caller.name,\n inviteeEmail: email,\n intendedRole: role,\n invitationUrl,\n expiresAt,\n appDisplayName: opts.appDisplayName,\n });\n\n try {\n await opts.sendEmail({\n to: email,\n subject: rendered.subject,\n html: rendered.html,\n text: rendered.text,\n });\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n return NextResponse.json(\n {\n invitationId: invitation.id.toString(),\n expiresAt: invitation.expires_at.toISOString(),\n warning: `invitation saved but email send failed: ${message}`,\n },\n { status: 202 },\n );\n }\n\n return NextResponse.json(\n {\n invitationId: invitation.id.toString(),\n expiresAt: invitation.expires_at.toISOString(),\n },\n { status: 201 },\n );\n },\n };\n\n return { send };\n}\n"],"mappings":";AAkBA,OAAO,cAIA;AACP,OAAO,iBAAiB;AACxB,OAAO,aAAa;AA+Eb,IAAM,YAAN,cAAwB,MAAM;AAAA,EACnC,YAAmB,MAAuC;AACxD,UAAM,IAAI;AADO;AAEjB,SAAK,OAAO;AAAA,EACd;AAAA,EAHmB;AAIrB;AAKO,SAAS,cAAc,SAA+C;AAC3E,SAAO,SAAS,MAAM,UAAU,CAAC;AACnC;AAGO,SAAS,SAAS,SAAqC,MAAuB;AACnF,MAAI,CAAC,QAAS,QAAO;AACrB,QAAM,SAAS,KAAK,YAAY;AAChC,SAAO,cAAc,OAAO,EAAE,KAAK,CAAC,MAAM,EAAE,YAAY,MAAM,MAAM;AACtE;AAOO,SAAS,aACd,YACG,OACG;AACN,MAAI,CAAC,QAAS,OAAM,IAAI,UAAU,iBAAiB;AACnD,MAAI,MAAM,WAAW,EAAG;AACxB,QAAM,KAAK,MAAM,KAAK,CAAC,MAAM,SAAS,SAAS,CAAC,CAAC;AACjD,MAAI,CAAC,GAAI,OAAM,IAAI,UAAU,WAAW;AAC1C;AAIA,SAAS,sBAAsB,cAAsB;AACnD,SAAO,CAAC,EAAE,KAAK,QAAQ,MAAgD;AACrE,QAAI;AACF,YAAM,SAAS,IAAI,IAAI,KAAK,OAAO;AACnC,YAAM,OAAO,aAAa,QAAQ,OAAO,EAAE,EAAE,YAAY;AACzD,YAAM,OAAO,OAAO,SAAS,YAAY;AACzC,YAAM,KAAK,SAAS,QAAQ,KAAK,SAAS,IAAI,IAAI,EAAE;AACpD,aAAO,KAAK,OAAO,SAAS,IAAI;AAAA,IAClC,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAIA,SAAS,iBAAiB,MAIf;AACT,MAAI,KAAK,WAAY,QAAO,KAAK;AACjC,SAAO,KAAK,cAAc,KAAK,OAAO,WAAW,WAAW,KAAK,IAAI;AACvE;AAIO,SAAS,WAAW,MAAyB;AAClD,QAAM,EAAE,QAAQ,YAAY,oBAAoB,IAAI;AACpD,QAAM,SAAS,KAAK,UAAU,QAAQ,IAAI,aAAa;AACvD,QAAM,eAAe,SAAS,OAAO,eAAe;AAIpD,QAAM,cACJ,QAAQ,IAAI,eAAe,4BAC3B,CAAC,QAAQ,IAAI;AAEf,MAAI,OAAO,SAAS,UAAU,CAAC,aAAa;AAC1C,QAAI,CAAC,OAAO,mBAAmB,CAAC,OAAO,eAAe;AACpD,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AACA,QAAI,UAAU,CAAC,qBAAqB;AAClC,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,QAAM,aAAa,iBAAiB;AAAA,IAClC,YAAY,KAAK;AAAA,IACjB,WAAW,OAAO;AAAA,IAClB,MAAM,OAAO;AAAA,EACf,CAAC;AAED,QAAM,yBAAyB,KAAK,WAAW,0BAA0B,CAAC;AAC1E,QAAM,kBAAkB,uBAAuB,SAAS;AACxD,QAAM,gBACJ,KAAK,WAAW,kBACf,OAAO,cAAc,OAAO,OACzB,kCAAkC,mBAAmB,OAAO,WAAW,MAAM,CAAC,KAC9E,WAAW,OAAO,IAAI,kCAAkC,mBAAmB,OAAO,WAAW,EAAE,CAAC;AAEtG,QAAM,SAAyB;AAAA,IAC7B,QAAQ;AAAA,IACR,SAAS,eACL;AAAA,MACE,cAAc;AAAA,QACZ,MAAM;AAAA,QACN,SAAS;AAAA,UACP,QAAQ;AAAA,UACR,UAAU;AAAA,UACV,QAAQ;AAAA,UACR,UAAU;AAAA,UACV,MAAM;AAAA,QACR;AAAA,MACF;AAAA,IACF,IACA;AAAA,IACJ,WAAW,SACP;AAAA,MACE,QAAQ;AAAA,QACN,UAAU,OAAO;AAAA,QACjB,cAAc;AAAA,QACd,QAAQ,OAAO;AAAA,MACjB,CAAC;AAAA,IACH,IACA;AAAA,MACE,YAAY;AAAA,QACV,MAAM;AAAA,QACN,aAAa;AAAA,UACX,MAAM;AAAA,YACJ,OAAO;AAAA,YACP,MAAM;AAAA,YACN,aAAa;AAAA,UACf;AAAA,QACF;AAAA,QACA,WAAW,OAAO,gBAAgB;AAChC,gBAAM,OAAO,aAAa;AAC1B,cAAI,CAAC,KAAM,QAAO;AAClB,gBAAM,UAAU,KAAK,OAAO,CAAC,EAAE,YAAY,IAAI,KAAK,MAAM,CAAC;AAC3D,iBAAO;AAAA,YACL,IAAI,QAAQ,IAAI;AAAA,YAChB,MAAM,GAAG,OAAO;AAAA,YAChB,OAAO,GAAG,IAAI;AAAA,YACd;AAAA,YACA,QAAQ,CAAC,IAAI;AAAA,UACf;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACH;AAAA,IACJ,SAAS,EAAE,UAAU,MAAM;AAAA,IAC3B,WAAW;AAAA,MACT,KAAK,CAAC,EAAE,OAAO,MAAM,SAAS,QAAQ,MAAM;AAC1C,YAAI,MAAM;AACR,gBAAM,QAAQ,KAAK,MAAM;AACzB,gBAAM,UAAU,KAAK,SAAS;AAC9B,cAAI,CAAC,QAAQ;AACX,kBAAM,IAAI;AACV,kBAAM,SAAS,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE,IAAI,IAAI,CAAC;AACjD,gBAAI,OAAO,SAAS,GAAG;AACrB,cAAC,MAAkC,gBAAgB,IAAI;AAAA,YACzD;AAAA,UACF;AAAA,QACF;AACA,YAAI,UAAU,SAAS;AACrB,gBAAM,SAAU,QAAoC,gBAAgB;AACpE,cAAI,QAAQ;AACV,YAAC,MAAkC,gBAAgB,IAAI;AAAA,UACzD;AAAA,QACF;AAIA,YAAI,SAAS,cAAc;AACzB,UAAC,MAAkC,aAAa,IAAI,QAAQ;AAAA,QAC9D;AACA,eAAO;AAAA,MACT;AAAA,MACA,SAAS,CAAC,EAAE,SAAS,MAAM,MAAM;AAC/B,cAAM,SACF,MAAkC,gBAAgB,KAElC,CAAC;AACrB,gBAAQ,KAAK,SAAS;AACtB,cAAM,cAAe,MAAkC,aAAa;AACpE,YAAI,OAAO,gBAAgB,UAAU;AACnC,kBAAQ,cAAc;AAAA,QACxB;AACA,eAAO;AAAA,MACT;AAAA,MACA,YAAY,CAAC,EAAE,MAAM,SAAS,SAAS,EAAE,QAAQ,EAAE,MAAM;AACvD,cAAM,OAAO,QAAQ;AACrB,cAAM,gBAAgB,KAAK,oBAAoB;AAAA,UAC7C,CAAC,WAAW,SAAS,UAAU,KAAK,WAAW,GAAG,MAAM,GAAG;AAAA,QAC7D;AACA,YAAI,CAAC,WAAW,eAAe;AAQ7B,cAAI,WAAW,WAAW,MAAM,GAAG;AACjC,kBAAM,SAAS,IAAI,IAAI,UAAU;AACjC,mBAAO,aAAa,IAAI,eAAe,QAAQ,IAAI;AACnD,mBAAO,SAAS,SAAS,OAAO,SAAS,GAAG,GAAG;AAAA,UACjD;AACA,iBAAO;AAAA,QACT;AAEA,YAAI,WAAW,iBAAiB,iBAAiB;AAC/C,gBAAM,cAAc,QAAQ,MAAM,UAAU,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,YAAY,CAAC;AAC1E,gBAAM,UAAU,uBAAuB;AAAA,YAAK,CAAC,MAC3C,WAAW,SAAS,EAAE,YAAY,CAAC;AAAA,UACrC;AACA,cAAI,CAAC,SAAS;AACZ,kBAAM,SAAS,cAAc,WAAW,MAAM,IAC1C,IAAI,IAAI,aAAa,IACrB,IAAI,IAAI,eAAe,QAAQ,MAAM;AACzC,mBAAO,SAAS,SAAS,OAAO,SAAS,GAAG,GAAG;AAAA,UACjD;AAAA,QACF;AACA,eAAO;AAAA,MACT;AAAA,MACA,UAAU,sBAAsB,OAAO,YAAY;AAAA,IACrD;AAAA,IACA,OAAO,EAAE,QAAQ,WAAW;AAAA,IAC5B,WAAW;AAAA,EACb;AAEA,SAAO,SAAS,MAAM;AACxB;;;AChVA,OAAO;AAEP,SAAS,eAAe;;;ACFxB,OAAO;AAEP,SAAS,QAAQ,cAAc;AAC/B,SAAS,iBAAiB;AAkBnB,IAAM,0BAA0B;AAChC,IAAM,0BAA0B;AACvC,IAAM,uBAAuB;AAa7B,IAAI,eAA8B;AAElC,eAAe,gBAAiC;AAC9C,MAAI,aAAc,QAAO;AACzB,QAAM,MAAM,QAAQ,IAAI;AACxB,QAAM,SAAS,MAAM,MAAM,UAAU,GAAG,IAAI;AAC5C,QAAM,SAAS,UAAU,QAAQ,IAAI;AACrC,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,iBAAe;AACf,SAAO;AACT;AAEA,eAAsB,uBAAuB,MAIG;AAC9C,QAAM,SAAS,MAAM,cAAc;AACnC,QAAM,SAAS,KAAK,OAAO,KAAK,KAAK,QAAQ,KAAK,KAAK,IAAI,KAAK,GAAI;AACpE,QAAM,MAAM,SAAS;AACrB,QAAM,QAAQ,MAAM,OAAO;AAAA,IACzB;AAAA,IACA,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,OAAO;AAAA,MACL,gBAAgB,OAAO,KAAK,OAAO;AAAA,MACnC,KAAK,OAAO,KAAK,QAAQ;AAAA,MACzB,KAAK;AAAA,MACL;AAAA,IACF;AAAA,EACF,CAAC;AACD,SAAO,EAAE,OAAO,WAAW,IAAI,KAAK,MAAM,GAAI,EAAE;AAClD;AAEA,eAAsB,yBACpB,OACqC;AACrC,MAAI;AACF,UAAM,SAAS,MAAM,cAAc;AACnC,UAAM,UAAU,MAAM,OAAO;AAAA,MAC3B;AAAA,MACA;AAAA,MACA,MAAM;AAAA,IACR,CAAC;AACD,QAAI,CAAC,QAAS,QAAO;AACrB,UAAM,iBAAiB,QAAQ,gBAAgB;AAC/C,UAAM,MAAM,QAAQ,KAAK;AACzB,UAAM,MAAM,QAAQ,KAAK;AACzB,UAAM,MAAM,QAAQ,KAAK;AACzB,QACE,OAAO,mBAAmB,YAC1B,OAAO,QAAQ,YACf,OAAO,QAAQ,YACf,OAAO,QAAQ,UACf;AACA,aAAO;AAAA,IACT;AACA,QAAI,MAAM,MAAO,KAAK,IAAI,EAAG,QAAO;AACpC,WAAO,EAAE,gBAAgB,KAAK,KAAK,IAAI;AAAA,EACzC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;;;ADQA,IAAM,2BACJ;AASK,SAAS,yBACd,MACgE;AAChE,QAAM,oBAAoB,KAAK,eAAe,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,YAAY,CAAC;AAC5E,QAAM,cAAc,KAAK,2BAA2B;AAEpD,SAAO,eAAe,mBACpB,SAC0C;AAC1C,UAAM,QAAQ,QAAQ,MAAM;AAC5B,QAAI,CAAC,OAAO;AACV,YAAM,IAAI,MAAM,iEAAiE;AAAA,IACnF;AAEA,UAAM,KAAK,MAAM,KAAK,GAAG;AAGzB,QAAI;AACF,YAAM,cAAc,MAAM,QAAQ;AAClC,YAAM,SAAS,YAAY,IAAI,uBAAuB;AACtD,UAAI,QAAQ,OAAO;AACjB,cAAM,SAAS,MAAM,yBAAyB,OAAO,KAAK;AAC1D,YAAI,QAAQ;AACV,gBAAM,CAAC,OAAO,MAAM,IAAI,MAAM,QAAQ,IAAI;AAAA,YACxC,GAAG,KAAK,WAAW,EAAE,OAAO,EAAE,IAAI,OAAO,eAAe,EAAE,CAAC;AAAA,YAC3D,GAAG,KAAK,WAAW,EAAE,OAAO,EAAE,IAAI,OAAO,IAAI,EAAE,CAAC;AAAA,UAClD,CAAC;AACD,cAAI,SAAS,MAAM,SAAS,WAAW,QAAQ;AAC7C,mBAAO,OAAO,OAAO,QAAQ;AAAA,cAC3B,gBAAgB,OAAO;AAAA,YACzB,CAAC;AAAA,UACH;AAAA,QAEF;AAAA,MACF;AAAA,IACF,QAAQ;AAAA,IAER;AAEA,UAAM,WAAW,MAAM,GAAG,KAAK,WAAW,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;AAC9D,QAAI,SAAU,QAAO;AAGrB,UAAM,SAAU,QAAQ,KAA+B,UAAU,CAAC;AAClE,UAAM,eAAe,iBAAiB,SAAS,MAAM,YAAY,CAAC,IAC9D,UACC,OAAO,CAAC,KAAK,KAAK;AACvB,UAAM,OAAQ,QAAQ,KAAkC,QAAQ,MAAM,MAAM,GAAG,EAAE,CAAC;AAElF,WAAO,GAAG,aAAa,OAAO,OAAO;AACnC,YAAM,gBAAgB,MAAM,GAAG,WAAW,UAAU;AAAA,QAClD,OAAO;AAAA,UACL;AAAA,UACA,aAAa;AAAA,UACb,YAAY,EAAE,IAAI,oBAAI,KAAK,EAAE;AAAA,QAC/B;AAAA,QACA,SAAS,EAAE,YAAY,OAAO;AAAA,MAChC,CAAC;AAED,YAAM,OAAO,gBAAgB,cAAc,gBAAgB;AAC3D,YAAM,YAAY,gBAAgB,cAAc,YAAY;AAE5D,YAAM,UAAU,MAAM,GAAG,KAAK,OAAO;AAAA,QACnC,MAAM;AAAA,UACJ;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA,UAAU;AAAA,UACV,gBAAgB,KAAK,qBAAqB,IAAI;AAAA,UAC9C,GAAI,KAAK,qBAAqB,CAAC;AAAA,QACjC;AAAA,MACF,CAAC;AAED,UAAI,eAAe;AACjB,cAAM,GAAG,WAAW,OAAO;AAAA,UACzB,OAAO,EAAE,IAAI,cAAc,GAAG;AAAA,UAC9B,MAAM;AAAA,YACJ,aAAa,oBAAI,KAAK;AAAA,YACtB,qBAAqB,QAAQ;AAAA,UAC/B;AAAA,QACF,CAAC;AAAA,MACH;AAEA,aAAO;AAAA,IACT,CAAC;AAAA,EACH;AACF;;;AE/MA,OAAO;AACP,SAAS,oBAAoB;AAwEtB,SAAS,gBAAgB,MAA8B;AAC5D,SAAO;AAAA,IACL,KAAK,YAAY;AACf,YAAM,UAAU,MAAM,KAAK,KAAK;AAChC,UAAI,CAAC,SAAS,MAAM;AAClB,eAAO,aAAa;AAAA,UAClB,EAAE,OAAO,gBAAgB,MAAM,eAAe;AAAA,UAC9C,EAAE,QAAQ,IAAI;AAAA,QAChB;AAAA,MACF;AACA,YAAM,KAAK,MAAM,KAAK,mBAAmB,OAAO;AAChD,UAAI,iBAAqE;AACzE,UAAI,GAAG,gBAAgB;AACrB,cAAM,KAAK,MAAM,KAAK,MAAM;AAC5B,cAAM,QAAQ,MAAM,GAAG,KAAK,WAAW;AAAA,UACrC,OAAO,EAAE,IAAI,OAAO,OAAO,GAAG,cAAc,CAAC,EAAE;AAAA,UAC/C,QAAQ,EAAE,IAAI,MAAM,MAAM,MAAM,OAAO,KAAK;AAAA,QAC9C,CAAC;AACD,YAAI,OAAO;AACT,2BAAiB;AAAA,YACf,IAAI,MAAM,GAAG,SAAS;AAAA,YACtB,MAAM,MAAM;AAAA,YACZ,OAAO,MAAM;AAAA,UACf;AAAA,QACF;AAAA,MACF;AACA,aAAO,aAAa,KAAK;AAAA,QACvB,MAAM;AAAA,UACJ,IAAI,GAAG,GAAG,SAAS;AAAA,UACnB,OAAO,GAAG;AAAA,UACV,MAAM,GAAG;AAAA,UACT,MAAM,GAAG;AAAA,UACT,WAAW,GAAG;AAAA,UACd,gBAAgB,OAAO,GAAG,cAAc;AAAA,QAC1C;AAAA,QACA;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAYA,SAAS,aAAa,OAA8B;AAClD,MAAI,CAAC,SAAS,KAAK,KAAK,EAAG,QAAO;AAClC,MAAI;AACF,WAAO,OAAO,KAAK;AAAA,EACrB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,0BAA0B,MAAwC;AAChF,QAAM,aAAa,KAAK,cAAc,CAAC,OAAO;AAC9C,QAAM,cAAc,CAAC,SACnB,WAAW,KAAK,CAAC,MAAM,EAAE,YAAY,MAAM,KAAK,YAAY,CAAC;AAE/D,SAAO;AAAA,IACL,MAAM,OACJ,UACA,QACsB;AACtB,YAAM,UAAU,MAAM,KAAK,KAAK;AAChC,UAAI,CAAC,SAAS,MAAM;AAClB,eAAO,aAAa;AAAA,UAClB,EAAE,OAAO,gBAAgB,MAAM,eAAe;AAAA,UAC9C,EAAE,QAAQ,IAAI;AAAA,QAChB;AAAA,MACF;AACA,YAAM,SAAS,MAAM,KAAK,mBAAmB,OAAO;AACpD,UAAI,CAAC,YAAY,OAAO,IAAI,KAAK,OAAO,gBAAgB;AACtD,eAAO,aAAa;AAAA,UAClB,EAAE,OAAO,aAAa,MAAM,YAAY;AAAA,UACxC,EAAE,QAAQ,IAAI;AAAA,QAChB;AAAA,MACF;AACA,YAAM,EAAE,GAAG,IAAI,MAAM,IAAI;AACzB,YAAM,WAAW,aAAa,EAAE;AAChC,UAAI,aAAa,MAAM;AACrB,eAAO,aAAa;AAAA,UAClB,EAAE,OAAO,cAAc,MAAM,aAAa;AAAA,UAC1C,EAAE,QAAQ,IAAI;AAAA,QAChB;AAAA,MACF;AACA,UAAI,aAAa,OAAO,OAAO,OAAO,EAAE,CAAC,GAAG;AAC1C,eAAO,aAAa;AAAA,UAClB,EAAE,OAAO,2BAA2B,MAAM,aAAa;AAAA,UACvD,EAAE,QAAQ,IAAI;AAAA,QAChB;AAAA,MACF;AACA,YAAM,KAAK,MAAM,KAAK,MAAM;AAC5B,YAAM,SAAS,MAAM,GAAG,KAAK,WAAW;AAAA,QACtC,OAAO,EAAE,IAAI,SAAS;AAAA,QACtB,QAAQ,EAAE,IAAI,MAAM,MAAM,MAAM,OAAO,MAAM,MAAM,KAAK;AAAA,MAC1D,CAAC;AACD,UAAI,CAAC,QAAQ;AACX,eAAO,aAAa;AAAA,UAClB,EAAE,OAAO,aAAa,MAAM,YAAY;AAAA,UACxC,EAAE,QAAQ,IAAI;AAAA,QAChB;AAAA,MACF;AACA,UAAI,OAAO,QAAQ,YAAY,OAAO,IAAI,GAAG;AAC3C,eAAO,aAAa;AAAA,UAClB,EAAE,OAAO,oCAAoC,MAAM,YAAY;AAAA,UAC/D,EAAE,QAAQ,IAAI;AAAA,QAChB;AAAA,MACF;AACA,YAAM,EAAE,OAAO,UAAU,IAAI,MAAM,uBAAuB;AAAA,QACxD,SAAS,OAAO,OAAO,OAAO,EAAE,CAAC;AAAA,QACjC,UAAU,OAAO,OAAO,OAAO,EAAE,CAAC;AAAA,MACpC,CAAC;AACD,YAAM,GAAG,YAAY,OAAO;AAAA,QAC1B,MAAM;AAAA,UACJ,SAAS,OAAO;AAAA,UAChB,QAAQ;AAAA,UACR,UAAU;AAAA,YACR,gBAAgB,OAAO,GAAG,SAAS;AAAA,YACnC,cAAc,OAAO;AAAA,YACrB,YAAY,UAAU,YAAY;AAAA,UACpC;AAAA,QACF;AAAA,MACF,CAAC;AACD,YAAM,MAAM,aAAa;AAAA,QACvB;AAAA,UACE,IAAI;AAAA,UACJ,QAAQ;AAAA,YACN,IAAI,OAAO,GAAG,SAAS;AAAA,YACvB,OAAO,OAAO;AAAA,YACd,MAAM,OAAO;AAAA,YACb,MAAM,OAAO;AAAA,UACf;AAAA,UACA,WAAW,UAAU,YAAY;AAAA,QACnC;AAAA,QACA,EAAE,QAAQ,IAAI;AAAA,MAChB;AACA,UAAI,QAAQ,IAAI;AAAA,QACd,MAAM;AAAA,QACN,OAAO;AAAA,QACP,UAAU;AAAA,QACV,QAAQ,QAAQ,IAAI,aAAa;AAAA,QACjC,UAAU;AAAA,QACV,MAAM;AAAA,QACN,QAAQ;AAAA,MACV,CAAC;AACD,aAAO;AAAA,IACT;AAAA,IACA,QAAQ,YAA+B;AACrC,YAAM,UAAU,MAAM,KAAK,KAAK;AAChC,UAAI,SAAS,MAAM;AACjB,YAAI;AACF,gBAAM,SAAS,MAAM,KAAK,mBAAmB,OAAO;AACpD,cAAI,OAAO,gBAAgB;AACzB,kBAAM,KAAK,MAAM,KAAK,MAAM;AAC5B,kBAAM,GAAG,YAAY,OAAO;AAAA,cAC1B,MAAM;AAAA,gBACJ,SAAS,OAAO,OAAO,OAAO,cAAc,CAAC;AAAA,gBAC7C,QAAQ;AAAA,gBACR,UAAU,EAAE,gBAAgB,OAAO,GAAG,SAAS,EAAE;AAAA,cACnD;AAAA,YACF,CAAC;AAAA,UACH;AAAA,QACF,QAAQ;AAAA,QAER;AAAA,MACF;AACA,YAAM,MAAM,aAAa,KAAK,EAAE,IAAI,KAAK,CAAC;AAC1C,UAAI,QAAQ,IAAI;AAAA,QACd,MAAM;AAAA,QACN,OAAO;AAAA,QACP,UAAU;AAAA,QACV,QAAQ,QAAQ,IAAI,aAAa;AAAA,QACjC,UAAU;AAAA,QACV,MAAM;AAAA,QACN,QAAQ;AAAA,MACV,CAAC;AACD,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAQO,SAAS,yBAAyB,MAAuC;AAU9E,QAAM,cAAc,OAAO,UAAqD;AAC9E,UAAM,KAAK,MAAM,KAAK,MAAM;AAC5B,UAAM,aAAa,MAAM,GAAG,WAAW,WAAW;AAAA,MAChD,OAAO,EAAE,MAAM;AAAA,MACf,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,KAAK,EAAE,EAAE;AAAA,IACjD,CAAC;AACD,QAAI,CAAC,WAAY,QAAO;AACxB,WAAO;AAAA,MACL,OAAO,WAAW;AAAA,MAClB,cAAc,WAAW,QAAQ;AAAA,MACjC,eAAe,WAAW;AAAA,MAC1B,YAAY,WAAW,WAAW,YAAY;AAAA,MAC9C,aAAa,WAAW,aAAa,YAAY,KAAK;AAAA,MACtD,SAAS,WAAW,WAAW,QAAQ,IAAI,KAAK,IAAI;AAAA,IACtD;AAAA,EACF;AAEA,QAAM,gBAAgB,CAAC,UAAmC;AACxD,QAAI,CAAC,SAAS,MAAM,SAAS,KAAK;AAChC,aAAO,aAAa;AAAA,QAClB,EAAE,OAAO,iBAAiB,MAAM,aAAa;AAAA,QAC7C,EAAE,QAAQ,IAAI;AAAA,MAChB;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAEA,SAAO;AAAA,IACL,KAAK,OACH,UACA,EAAE,OAAO,MACa;AACtB,YAAM,EAAE,MAAM,IAAI,MAAM;AACxB,YAAM,UAAU,cAAc,KAAK;AACnC,UAAI,QAAS,QAAO;AACpB,YAAM,UAAU,MAAM,YAAY,KAAK;AACvC,UAAI,CAAC,SAAS;AACZ,eAAO,aAAa;AAAA,UAClB,EAAE,OAAO,wBAAwB,MAAM,YAAY;AAAA,UACnD,EAAE,QAAQ,IAAI;AAAA,QAChB;AAAA,MACF;AACA,aAAO,aAAa,KAAK,OAAO;AAAA,IAClC;AAAA,IACA,MAAM,OACJ,UACA,EAAE,OAAO,MACa;AACtB,YAAM,EAAE,MAAM,IAAI,MAAM;AACxB,YAAM,UAAU,cAAc,KAAK;AACnC,UAAI,QAAS,QAAO;AACpB,YAAM,UAAU,MAAM,YAAY,KAAK;AACvC,UAAI,CAAC,SAAS;AACZ,eAAO,aAAa;AAAA,UAClB,EAAE,OAAO,wBAAwB,MAAM,YAAY;AAAA,UACnD,EAAE,QAAQ,IAAI;AAAA,QAChB;AAAA,MACF;AACA,aAAO,aAAa,KAAK,EAAE,IAAI,MAAM,GAAG,QAAQ,CAAC;AAAA,IACnD;AAAA,EACF;AACF;;;AClVA,OAAO;AACP,SAAS,gBAAAA,qBAAoB;AAmE7B,SAAS,eAAe,SAAwC;AAC9D,MAAI,CAAC,QAAS,QAAO;AACrB,QAAM,UAAW,QAAgD;AACjE,MAAI,OAAO,YAAY,YAAY,QAAQ,SAAS,EAAG,QAAO;AAC9D,SAAO;AACT;AAEA,SAAS,6BAA6B;AACpC,SAAOA,cAAa;AAAA,IAClB;AAAA,MACE,OACE;AAAA,MACF,MAAM;AAAA,IACR;AAAA,IACA,EAAE,QAAQ,IAAI;AAAA,EAChB;AACF;AAEA,SAAS,eAAe,SAAiB;AACvC,SAAOA,cAAa,KAAK,EAAE,OAAO,SAAS,MAAM,aAAa,GAAG,EAAE,QAAQ,IAAI,CAAC;AAClF;AAEO,SAAS,uBAAuB,MAAqC;AAE1E,QAAM,iBAAiB;AAAA,IACrB,MAAM,OAAO,YAAwC;AACnD,YAAM,UAAU,MAAM,KAAK,KAAK;AAChC,UAAI,CAAC,SAAS,MAAM;AAClB,eAAOA,cAAa,KAAK,EAAE,OAAO,eAAe,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,MACrE;AACA,YAAM,cAAc,eAAe,OAAO;AAC1C,UAAI,CAAC,YAAa,QAAO,2BAA2B;AAEpD,UAAI;AACJ,UAAI;AACF,eAAQ,MAAM,QAAQ,KAAK;AAAA,MAC7B,QAAQ;AACN,eAAO,eAAe,mBAAmB;AAAA,MAC3C;AACA,YAAM,kBACJ,OAAO,KAAK,oBAAoB,WAAW,KAAK,kBAAkB;AACpE,YAAM,cAAc,OAAO,KAAK,gBAAgB,WAAW,KAAK,cAAc;AAC9E,UAAI,CAAC,gBAAiB,QAAO,eAAe,0BAA0B;AACtE,UAAI,YAAY,SAAS;AACvB,eAAO,eAAe,sCAAsC;AAE9D,UAAI;AACF,cAAM,KAAK,QAAQ,eAAe;AAAA,UAChC;AAAA,UACA,kBAAkB;AAAA,UAClB,kBAAkB;AAAA,QACpB,CAAC;AACD,cAAM,UAAU,MAAM,KAAK,mBAAmB,OAAO;AACrD,cAAM,KAAK,MAAM,KAAK,MAAM;AAC5B,cAAM,GAAG,KAAK,OAAO;AAAA,UACnB,OAAO,EAAE,IAAI,QAAQ,GAAG;AAAA,UACxB,MAAM,EAAE,sBAAsB,MAAM;AAAA,QACtC,CAAC;AACD,eAAOA,cAAa,KAAK,EAAE,IAAI,KAAK,CAAC;AAAA,MACvC,SAAS,KAAK;AACZ,cAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC/D,eAAOA,cAAa,KAAK,EAAE,OAAO,SAAS,MAAM,UAAU,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,MAC/E;AAAA,IACF;AAAA,EACF;AAGA,QAAM,iBAAiB;AAAA,IACrB,MAAM,YAA+B;AACnC,YAAM,UAAU,MAAM,KAAK,KAAK;AAChC,UAAI,CAAC,SAAS,MAAM;AAClB,eAAOA,cAAa,KAAK,EAAE,OAAO,eAAe,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,MACrE;AACA,YAAM,cAAc,eAAe,OAAO;AAC1C,UAAI,CAAC,YAAa,QAAO,2BAA2B;AACpD,UAAI;AACF,cAAM,EAAE,WAAW,IAAI,MAAM,KAAK,QAAQ,uBAAuB;AAAA,UAC/D;AAAA,QACF,CAAC;AACD,cAAM,cAAc,QAAQ,KAAK,SAAS;AAC1C,cAAM,aAAa,KAAK,QAAQ,gBAAgB;AAAA,UAC9C,QAAQ;AAAA,UACR;AAAA,UACA,QAAQ,KAAK;AAAA,QACf,CAAC;AACD,cAAM,YAAY,KAAK,oBACnB,MAAM,KAAK,kBAAkB,UAAU,EAAE,MAAM,MAAM,EAAE,IACvD;AACJ,eAAOA,cAAa,KAAK,EAAE,WAAW,YAAY,QAAQ,WAAW,CAAC;AAAA,MACxE,SAAS,KAAK;AACZ,cAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC/D,eAAOA,cAAa,KAAK,EAAE,OAAO,SAAS,MAAM,UAAU,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,MAC/E;AAAA,IACF;AAAA,EACF;AAGA,QAAM,kBAAkB;AAAA,IACtB,MAAM,OAAO,YAAwC;AACnD,YAAM,UAAU,MAAM,KAAK,KAAK;AAChC,UAAI,CAAC,SAAS,MAAM;AAClB,eAAOA,cAAa,KAAK,EAAE,OAAO,eAAe,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,MACrE;AACA,YAAM,cAAc,eAAe,OAAO;AAC1C,UAAI,CAAC,YAAa,QAAO,2BAA2B;AACpD,UAAI;AACJ,UAAI;AACF,eAAQ,MAAM,QAAQ,KAAK;AAAA,MAC7B,QAAQ;AACN,eAAO,eAAe,mBAAmB;AAAA,MAC3C;AACA,YAAM,OAAO,OAAO,KAAK,SAAS,WAAW,KAAK,OAAO;AACzD,UAAI,CAAC,aAAa,KAAK,IAAI,EAAG,QAAO,eAAe,uBAAuB;AAC3E,UAAI;AACF,cAAM,SAAS,MAAM,KAAK,QAAQ,oBAAoB,EAAE,aAAa,KAAK,CAAC;AAC3E,YAAI,OAAO,WAAW,WAAW;AAC/B,iBAAOA,cAAa;AAAA,YAClB,EAAE,OAAO,kBAAkB,OAAO,MAAM,IAAI,MAAM,gBAAgB;AAAA,YAClE,EAAE,QAAQ,IAAI;AAAA,UAChB;AAAA,QACF;AACA,cAAM,KAAK,QAAQ,qBAAqB,EAAE,aAAa,SAAS,KAAK,CAAC;AACtE,cAAM,UAAU,MAAM,KAAK,mBAAmB,OAAO;AACrD,cAAM,KAAK,MAAM,KAAK,MAAM;AAC5B,cAAM,GAAG,KAAK,OAAO;AAAA,UACnB,OAAO,EAAE,IAAI,QAAQ,GAAG;AAAA,UACxB,MAAM,EAAE,yBAAyB,oBAAI,KAAK,EAAE;AAAA,QAC9C,CAAC;AACD,eAAOA,cAAa,KAAK,EAAE,IAAI,KAAK,CAAC;AAAA,MACvC,SAAS,KAAK;AACZ,cAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC/D,eAAOA,cAAa,KAAK,EAAE,OAAO,SAAS,MAAM,UAAU,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,MAC/E;AAAA,IACF;AAAA,EACF;AAGA,QAAM,mBAAmB;AAAA,IACvB,MAAM,YAA+B;AACnC,YAAM,UAAU,MAAM,KAAK,KAAK;AAChC,UAAI,CAAC,SAAS,MAAM;AAClB,eAAOA,cAAa,KAAK,EAAE,OAAO,eAAe,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,MACrE;AACA,YAAM,cAAc,eAAe,OAAO;AAC1C,UAAI,CAAC,YAAa,QAAO,2BAA2B;AACpD,UAAI;AACF,cAAM,KAAK,QAAQ,qBAAqB,EAAE,aAAa,SAAS,MAAM,CAAC;AACvE,cAAM,UAAU,MAAM,KAAK,mBAAmB,OAAO;AACrD,cAAM,KAAK,MAAM,KAAK,MAAM;AAC5B,cAAM,GAAG,KAAK,OAAO;AAAA,UACnB,OAAO,EAAE,IAAI,QAAQ,GAAG;AAAA,UACxB,MAAM,EAAE,yBAAyB,KAAK;AAAA,QACxC,CAAC;AACD,eAAOA,cAAa,KAAK,EAAE,IAAI,KAAK,CAAC;AAAA,MACvC,SAAS,KAAK;AACZ,cAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC/D,eAAOA,cAAa,KAAK,EAAE,OAAO,SAAS,MAAM,UAAU,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,MAC/E;AAAA,IACF;AAAA,EACF;AAEA,SAAO,EAAE,gBAAgB,gBAAgB,iBAAiB,iBAAiB;AAC7E;;;ACtOA,OAAO;AACP,SAAS,gBAAAC,qBAAoB;AAiF7B,SAAS,eAAyB;AAChC,SAAOA,cAAa;AAAA,IAClB,EAAE,OAAO,gBAAgB,MAAM,eAAe;AAAA,IAC9C,EAAE,QAAQ,IAAI;AAAA,EAChB;AACF;AAEA,SAASC,gBAAe,QAA2B;AACjD,SAAOD,cAAa,KAAK,EAAE,OAAO,gBAAgB,OAAO,GAAG,EAAE,QAAQ,IAAI,CAAC;AAC7E;AAEA,SAAS,YACP,SACA,QACA,MACA;AACA,SAAO,OAAO,YAAwC;AACpD,UAAM,UAAU,MAAM,KAAK,KAAK;AAChC,QAAI,CAAC,SAAS,KAAM,QAAO,aAAa;AAExC,QAAI;AACJ,QAAI;AACF,aAAO,MAAM,QAAQ,KAAK;AAAA,IAC5B,QAAQ;AACN,aAAOA,cAAa;AAAA,QAClB,EAAE,OAAO,gBAAgB,MAAM,aAAa;AAAA,QAC5C,EAAE,QAAQ,IAAI;AAAA,MAChB;AAAA,IACF;AAEA,UAAM,SAAS,OAAO,OAAO,UAAU,IAAI;AAC3C,QAAI,CAAC,OAAO,QAAS,QAAOC,gBAAe,OAAO,MAAM,MAAM;AAE9D,UAAM,OAAO,MAAM,KAAK,mBAAmB,OAAO;AAClD,UAAM,QAAQ,OAAO,QAAQ,OAAO,IAAI;AACxC,UAAM,KAAK,MAAM,KAAK,MAAM;AAC5B,UAAM,UAAU,MAAM,GAAG,KAAK,OAAO;AAAA,MACnC,OAAO,EAAE,IAAI,KAAK,GAAG;AAAA,MACrB,MAAM;AAAA,MACN,GAAI,OAAO,SAAS,EAAE,QAAQ,OAAO,OAAO,IAAI,CAAC;AAAA,IACnD,CAAC;AAED,QAAI,KAAK,aAAa;AACpB,YAAM,KAAK,YAAY,MAAM,SAAS,KAAK;AAAA,IAC7C;AAEA,WAAOD,cAAa,KAAK,OAAO;AAAA,EAClC;AACF;AAEO,SAAS,8BAGd,MAA4E;AAC5E,SAAO;AAAA,IACL,SAAS,EAAE,OAAO,YAAY,WAAW,KAAK,SAAS,SAAS,IAAI,EAAE;AAAA,IACtE,SAAS,EAAE,OAAO,YAAY,WAAW,KAAK,SAAS,SAAS,IAAI,EAAE;AAAA,EACxE;AACF;;;AC5IA,OAAO;AACP,SAAS,mBAAmB;AAC5B,SAAS,gBAAAE,qBAAoB;AAyBtB,IAAM,uBAAuB;AAG7B,SAAS,iCAAyC;AACvD,SAAO,YAAY,EAAE,EAAE,SAAS,WAAW;AAC7C;AAEO,SAAS,2BAA2B,MAAY,oBAAI,KAAK,GAAS;AACvE,QAAM,UAAU,IAAI,KAAK,GAAG;AAC5B,UAAQ,SAAS,QAAQ,SAAS,IAAI,oBAAoB;AAC1D,SAAO;AACT;AAEO,SAAS,0BAA0B,OAAe,QAAwB;AAE/E,QAAM,UAAU,OAAO,QAAQ,SAAS,EAAE;AAC1C,SAAO,GAAG,OAAO,gBAAgB,KAAK;AACxC;AAEO,SAAS,6BAA6B,KAA4C;AACvF,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI;AACJ,QAAM,UAAU,GAAG,cAAc;AACjC,QAAM,aAAa,UAAU,YAAY;AACzC,QAAM,OAAO;AAAA;AAAA;AAAA,4EAG6D,WAAW,cAAc,CAAC;AAAA,SAC7F,WAAW,WAAW,CAAC,oBAAoB,WAAW,YAAY,CAAC,2CAA2C,WAAW,YAAY,CAAC;AAAA;AAAA,iBAE9H,WAAW,aAAa,CAAC;AAAA;AAAA,0EAEgC,WAAW,UAAU,CAAC;AAAA;AAAA;AAG9F,QAAM,OAAO;AAAA,IACX,0BAA0B,cAAc;AAAA,IACxC;AAAA,IACA,GAAG,WAAW,YAAY,YAAY,0BAA0B,YAAY;AAAA,IAC5E;AAAA,IACA,0BAA0B,aAAa;AAAA,IACvC;AAAA,IACA,8BAA8B,UAAU;AAAA,EAC1C,EAAE,KAAK,IAAI;AACX,SAAO,EAAE,SAAS,MAAM,KAAK;AAC/B;AAEA,SAAS,WAAW,GAAmB;AACrC,SAAO,EACJ,QAAQ,MAAM,OAAO,EACrB,QAAQ,MAAM,MAAM,EACpB,QAAQ,MAAM,MAAM,EACpB,QAAQ,MAAM,QAAQ,EACtB,QAAQ,MAAM,OAAO;AAC1B;AAEA,SAAS,WAAW,GAAmB;AACrC,SAAO,WAAW,CAAC;AACrB;AAoFA,IAAM,WAAW;AACjB,IAAM,UAAU;AAChB,IAAM,YAAY;AAElB,SAAS,UAAU,QAAgB,OAAe,MAAc,OAAgB;AAC9E,SAAOA,cAAa,KAAK,EAAE,OAAO,MAAM,GAAI,SAAS,CAAC,EAAG,GAAG,EAAE,OAAO,CAAC;AACxE;AAEO,SAAS,6BAA6B,MAA2C;AACtF,QAAM,0BACJ,KAAK,2BAA2B;AAClC,QAAM,sBAAsB,KAAK,uBAAuB;AACxD,QAAM,qBAAqB,KAAK,sBAAsB;AACtD,QAAM,wBACJ,KAAK,yBAAyB;AAChC,QAAM,OAAO;AAAA,IACX,MAAM,OAAO,YAAwC;AACnD,YAAM,UAAU,MAAM,KAAK,KAAK;AAChC,UAAI,CAAC,SAAS,KAAM,QAAO,UAAU,KAAK,gBAAgB,cAAc;AAExE,YAAM,SAAS,MAAM,KAAK,mBAAmB,OAAO;AACpD,UAAI,CAAC,KAAK,UAAU,OAAO,IAAI,GAAG;AAChC,eAAO,UAAU,KAAK,aAAa,WAAW;AAAA,MAChD;AAEA,UAAI;AACJ,UAAI;AACF,eAAQ,MAAM,QAAQ,KAAK;AAAA,MAC7B,QAAQ;AACN,eAAO,UAAU,KAAK,qBAAqB,YAAY;AAAA,MACzD;AACA,YAAM,QAAQ,OAAO,KAAK,UAAU,WAAW,KAAK,MAAM,KAAK,EAAE,YAAY,IAAI;AACjF,YAAM,OAAO,OAAO,KAAK,SAAS,WAAW,KAAK,KAAK,KAAK,IAAI;AAChE,YAAM,cAAc,KAAK;AACzB,UAAI,CAAC,SAAS,KAAK,KAAK,KAAK,MAAM,SAAS,KAAK;AAC/C,eAAO,UAAU,KAAK,iBAAiB,YAAY;AAAA,MACrD;AACA,UAAI,CAAC,QAAQ,KAAK,SAAS,MAAM,CAAC,QAAQ,KAAK,IAAI,GAAG;AACpD,eAAO,UAAU,KAAK,qCAAqC,YAAY;AAAA,MACzE;AACA,UAAI,KAAK,gBAAgB,CAAC,KAAK,aAAa,SAAS,IAAI,GAAG;AAC1D,eAAO;AAAA,UACL;AAAA,UACA,wBAAwB,KAAK,aAAa,KAAK,IAAI,CAAC;AAAA,UACpD;AAAA,QACF;AAAA,MACF;AACA,UAAI,iBAAgC;AACpC,UAAI,gBAAgB,UAAa,gBAAgB,MAAM;AACrD,YAAI,OAAO,gBAAgB,YAAY,CAAC,UAAU,KAAK,WAAW,GAAG;AACnE,iBAAO;AAAA,YACL;AAAA,YACA;AAAA,YACA;AAAA,UACF;AAAA,QACF;AACA,yBAAiB,OAAO,WAAW;AAAA,MACrC;AAEA,YAAM,YAAY,KAAK,mBAAmB,QAAQ,cAAc;AAEhE,YAAM,KAAK,MAAM,KAAK,MAAM;AAC5B,YAAM,WAAW,MAAM,GAAG,KAAK,WAAW,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;AAC9D,UAAI,UAAU;AACZ,eAAO,UAAU,KAAK,uCAAuC,UAAU;AAAA,MACzE;AAEA,YAAM,QAAQ,wBAAwB;AACtC,YAAM,YAAY,oBAAoB;AACtC,YAAM,aAAa,MAAM,GAAG,WAAW,OAAO;AAAA,QAC5C,MAAM;AAAA,UACJ;AAAA,UACA;AAAA,UACA,YAAY,OAAO;AAAA,UACnB,eAAe;AAAA,UACf;AAAA,UACA,YAAY;AAAA,QACd;AAAA,MACF,CAAC;AAED,YAAM,SAAS,KAAK,eAChB,WAAW,KAAK,YAAY,KAC5B,IAAI,IAAI,QAAQ,GAAG,EAAE;AACzB,YAAM,gBAAgB,mBAAmB,OAAO,MAAM;AACtD,YAAM,WAAW,sBAAsB;AAAA,QACrC,aAAa,OAAO;AAAA,QACpB,cAAc;AAAA,QACd,cAAc;AAAA,QACd;AAAA,QACA;AAAA,QACA,gBAAgB,KAAK;AAAA,MACvB,CAAC;AAED,UAAI;AACF,cAAM,KAAK,UAAU;AAAA,UACnB,IAAI;AAAA,UACJ,SAAS,SAAS;AAAA,UAClB,MAAM,SAAS;AAAA,UACf,MAAM,SAAS;AAAA,QACjB,CAAC;AAAA,MACH,SAAS,KAAK;AACZ,cAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC/D,eAAOA,cAAa;AAAA,UAClB;AAAA,YACE,cAAc,WAAW,GAAG,SAAS;AAAA,YACrC,WAAW,WAAW,WAAW,YAAY;AAAA,YAC7C,SAAS,2CAA2C,OAAO;AAAA,UAC7D;AAAA,UACA,EAAE,QAAQ,IAAI;AAAA,QAChB;AAAA,MACF;AAEA,aAAOA,cAAa;AAAA,QAClB;AAAA,UACE,cAAc,WAAW,GAAG,SAAS;AAAA,UACrC,WAAW,WAAW,WAAW,YAAY;AAAA,QAC/C;AAAA,QACA,EAAE,QAAQ,IAAI;AAAA,MAChB;AAAA,IACF;AAAA,EACF;AAEA,SAAO,EAAE,KAAK;AAChB;","names":["NextResponse","NextResponse","jsonValidation","NextResponse"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@augmenting-integrations/auth",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.10.0",
|
|
4
4
|
"description": "Auth.js v5 factory + JIT user provisioning + impersonation + client-side user menu / sign-out. Subpath exports: /server (createAuth, JIT, impersonation token mint/verify) and /client (AppUserProvider, useAppUser, UserMenu, SignOutButton, ImpersonationBanner).",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"publishConfig": {
|
|
@@ -27,25 +27,27 @@
|
|
|
27
27
|
"README.md"
|
|
28
28
|
],
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"lucide-react": "^1.14.0"
|
|
30
|
+
"lucide-react": "^1.14.0",
|
|
31
|
+
"zod": "^4.1.7"
|
|
31
32
|
},
|
|
32
33
|
"peerDependencies": {
|
|
33
34
|
"next": "^16.0.0",
|
|
34
35
|
"next-auth": "^5.0.0-beta.31",
|
|
35
36
|
"react": "^19.0.0",
|
|
36
|
-
"@augmenting-integrations/aws": "8.
|
|
37
|
-
"@augmenting-integrations/platform": "8.
|
|
37
|
+
"@augmenting-integrations/aws": "8.10.0",
|
|
38
|
+
"@augmenting-integrations/platform": "8.10.0"
|
|
38
39
|
},
|
|
39
40
|
"devDependencies": {
|
|
40
41
|
"@types/react": "^19.0.0",
|
|
41
42
|
"next": "^16.2.5",
|
|
42
43
|
"next-auth": "^5.0.0-beta.31",
|
|
43
44
|
"react": "^19.0.0",
|
|
45
|
+
"server-only": "^0.0.1",
|
|
44
46
|
"tsup": "^8.3.5",
|
|
45
47
|
"typescript": "^5.7.2",
|
|
46
48
|
"vitest": "^4.1.5",
|
|
47
|
-
"@augmenting-integrations/
|
|
48
|
-
"@augmenting-integrations/
|
|
49
|
+
"@augmenting-integrations/platform": "8.10.0",
|
|
50
|
+
"@augmenting-integrations/aws": "8.10.0"
|
|
49
51
|
},
|
|
50
52
|
"scripts": {
|
|
51
53
|
"build": "tsup",
|