@ghuri/socialauth 0.1.0-alpha.0 → 0.1.0-alpha.1
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/index.js +1 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -311,8 +311,7 @@ import {
|
|
|
311
311
|
OAuthError,
|
|
312
312
|
OIDCStrategy,
|
|
313
313
|
profileFromClaims,
|
|
314
|
-
providerFetch
|
|
315
|
-
readBody
|
|
314
|
+
providerFetch
|
|
316
315
|
} from "@ghuri/oauth";
|
|
317
316
|
var Provider = class {
|
|
318
317
|
/** Several apps per provider, each with its own `providerId` (OpenID Connect). */
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/adapter.ts","../src/settings.ts","../src/apps.ts","../src/migrations/index.ts","../src/migrations/0001_initial.ts","../src/login.ts","../src/signals.ts","../src/tokens.ts","../src/providers.ts","../src/resolve.ts","../src/views.ts"],"sourcesContent":["// The adapter (django-allauth's DefaultSocialAccountAdapter): override to customize signup and linking.\nimport { getUserModel } from '@ghuri/auth'\nimport { reverse } from '@ghuri/core'\nimport type { Context } from 'hono'\nimport type { SocialLogin } from './login'\nimport type { SocialAccount } from './models'\nimport { socialSettings } from './settings'\n\n/** Throw from `preSocialLogin()` to answer with your own response. */\nexport class ImmediateResponse extends Error {\n constructor(readonly response: Response) {\n super('ImmediateResponse')\n }\n}\n\nexport interface SignupData {\n username?: string\n email?: string\n}\n\nconst USERNAME_ALLOWED = /[^\\w.@+-]/g\n\nexport class SocialAccountAdapter {\n /** May new users sign up through social login? */\n isOpenForSignup(_c: Context, _login: SocialLogin): boolean | Promise<boolean> {\n return true\n }\n\n /** Called after the provider answered, before anything is looked up or created. */\n async preSocialLogin(_c: Context, _login: SocialLogin): Promise<void> {}\n\n /** May the user be created without showing the signup form? */\n isAutoSignupAllowed(_c: Context, login: SocialLogin): boolean | Promise<boolean> {\n const s = socialSettings()\n if (!s.autoSignup) return false\n if (s.emailRequired && !login.profile.email) return false\n return true\n }\n\n /** A new, unsaved user instance. */\n newUser(_c: Context, _login: SocialLogin): any {\n const User = getUserModel()\n return new (User as any)()\n }\n\n /** Copy profile data (and signup form data) onto the new user. */\n populateUser(_c: Context, login: SocialLogin, user: any, data: SignupData): any {\n const M = user.constructor as { USERNAME_FIELD: string; EMAIL_FIELD: string; _meta: any }\n const has = (f: string) => !!M._meta.getField?.(f)\n if (data.username !== undefined) user[M.USERNAME_FIELD] = data.username\n if (data.email !== undefined && has(M.EMAIL_FIELD)) user[M.EMAIL_FIELD] = data.email\n if (has('firstName') && login.profile.firstName) user.firstName = login.profile.firstName.slice(0, 150)\n if (has('lastName') && login.profile.lastName) user.lastName = login.profile.lastName.slice(0, 150)\n if (has('firstName') && !login.profile.firstName && login.profile.name && has('lastName')) {\n const [first, ...rest] = login.profile.name.trim().split(/\\s+/)\n user.firstName = (first ?? '').slice(0, 150)\n user.lastName = rest.join(' ').slice(0, 150)\n }\n return user\n }\n\n /** Save the new user (with an unusable password). */\n async saveUser(_c: Context, _login: SocialLogin, user: any): Promise<any> {\n if (typeof user.setUnusablePassword === 'function') user.setUnusablePassword()\n await user.save()\n return user\n }\n\n /** Username candidates, best first. */\n usernameCandidates(login: SocialLogin): string[] {\n const p = login.profile\n return [p.username, p.email?.split('@')[0], p.name, p.firstName, `${login.key}${p.id}`].filter(\n (v): v is string => typeof v === 'string' && v.trim().length > 0,\n )\n }\n\n /** A username that is free, from the profile. */\n async generateUsername(_c: Context, login: SocialLogin): Promise<string> {\n const User = getUserModel()\n const field = User.USERNAME_FIELD\n const maxLength = (User._meta.getField(field) as { maxLength?: number } | undefined)?.maxLength ?? 150\n const taken = async (name: string) => User.objects.filter({ [`${field}__iexact`]: name } as any).exists()\n for (const raw of this.usernameCandidates(login)) {\n const base = raw.trim().replace(/\\s+/g, '').replace(USERNAME_ALLOWED, '').slice(0, maxLength)\n if (!base) continue\n if (!(await taken(base))) return base\n for (let i = 2; i < 100; i++) {\n const suffix = String(i)\n const candidate = `${base.slice(0, maxLength - suffix.length)}${suffix}`\n if (!(await taken(candidate))) return candidate\n }\n }\n return `user${crypto.randomUUID().replace(/-/g, '').slice(0, 12)}`\n }\n\n /** Where to go after connecting an account. */\n getConnectRedirectUrl(_c: Context, _account: SocialAccount): string {\n try {\n return reverse('socialaccount_connections')\n } catch {\n return '/'\n }\n }\n\n /** Customize error responses; return undefined for the default. */\n authenticationError(\n _c: Context,\n _error: { provider: string; message: string; code?: string },\n ): Response | undefined | Promise<Response | undefined> {\n return undefined\n }\n}\n\nconst cache = new WeakMap<object, SocialAccountAdapter>()\nlet fallback: SocialAccountAdapter | undefined\n\nexport function getAdapter(): SocialAccountAdapter {\n const cls = socialSettings().adapter\n if (!cls) {\n fallback ??= new SocialAccountAdapter()\n return fallback\n }\n let a = cache.get(cls)\n if (!a) {\n a = new cls()\n cache.set(cls, a)\n }\n return a\n}\n","import { tryGetContext } from '@ghuri/core'\n\n/** Credentials of one provider app, as in settings (`PROVIDERS.github.APP`) or a `SocialApp` row. */\nexport interface AppSettings {\n clientId: string\n secret?: string\n key?: string\n /** For `openid_connect`: the id used in URLs (`/accounts/okta/login/`). */\n providerId?: string\n name?: string\n /** Provider-specific settings (`serverUrl` for OpenID Connect, `tenant` for Microsoft…). */\n settings?: Record<string, unknown>\n}\n\nexport interface ProviderSettings {\n APP?: AppSettings\n /** Several apps of one provider (`openid_connect`). */\n APPS?: AppSettings[]\n SCOPE?: string[]\n AUTH_PARAMS?: Record<string, string>\n /** Override whether this provider's emails count as verified. */\n VERIFIED_EMAIL?: boolean\n [key: string]: unknown\n}\n\nexport interface SocialAccountSettings {\n PROVIDERS?: Record<string, ProviderSettings>\n ADAPTER?: new () => import('./adapter').SocialAccountAdapter\n AUTO_SIGNUP?: boolean\n EMAIL_AUTHENTICATION?: boolean\n EMAIL_REQUIRED?: boolean\n LOGIN_ON_GET?: boolean\n STORE_TOKENS?: boolean\n LOGIN_RESPONSE?: 'session' | 'jwt'\n FRONTEND_URL?: string\n /** Where browser flows go on errors (default `LOGIN_URL`), with `?error=`. */\n LOGIN_ERROR_URL?: string\n}\n\nexport interface ResolvedSocialSettings {\n providers: Record<string, ProviderSettings>\n adapter?: new () => import('./adapter').SocialAccountAdapter\n autoSignup: boolean\n emailAuthentication: boolean\n emailRequired: boolean\n loginOnGet: boolean\n storeTokens: boolean\n loginResponse: 'session' | 'jwt'\n frontendUrl?: string\n loginErrorUrl: string\n}\n\nexport function socialSettings(): ResolvedSocialSettings {\n const settings = (tryGetContext()?.settings ?? {}) as Record<string, unknown>\n const s = (settings.SOCIALACCOUNT ?? {}) as SocialAccountSettings\n return {\n providers: s.PROVIDERS ?? {},\n adapter: s.ADAPTER,\n autoSignup: s.AUTO_SIGNUP ?? true,\n emailAuthentication: s.EMAIL_AUTHENTICATION ?? false,\n emailRequired: s.EMAIL_REQUIRED ?? false,\n loginOnGet: s.LOGIN_ON_GET ?? false,\n storeTokens: s.STORE_TOKENS ?? false,\n loginResponse: s.LOGIN_RESPONSE ?? 'session',\n frontendUrl: s.FRONTEND_URL,\n loginErrorUrl: s.LOGIN_ERROR_URL ?? (settings.LOGIN_URL as string | undefined) ?? '/accounts/login/',\n }\n}\n","import * as auth from '@ghuri/auth'\nimport { AppConfig, apps, ImproperlyConfigured } from '@ghuri/core'\nimport * as migrations from './migrations/index'\nimport { SocialAccount, SocialApp, SocialToken } from './models'\n\nfunction appPath(): string | undefined {\n const meta = import.meta as ImportMeta & { dirname?: string; filename?: string }\n const dir = meta.dirname\n if (!dir || !/[\\\\/]src$/.test(dir) || !/\\.[cm]?ts$/.test(meta.filename ?? '')) return undefined\n return dir\n}\n\nfunction migrationsModule(): Record<string, unknown> {\n const adapt = (auth as Record<string, any>).migrationsForUserModel\n return typeof adapt === 'function' ? adapt('socialaccount', migrations) : migrations\n}\n\n/** The `socialaccount` app (django-allauth's): `SocialApp`, `SocialAccount`, `SocialToken`. */\nexport class SocialAuthConfig extends AppConfig {\n name = '@ghuri/socialauth'\n override label = 'socialaccount'\n override verboseName = 'Social Accounts'\n override path = appPath()\n override migrations = migrationsModule()\n override models = { SocialApp, SocialAccount, SocialToken }\n\n override ready(): void {\n if (!apps.isInstalled('auth')) {\n throw new ImproperlyConfigured(\n \"'socialaccount' requires '@ghuri/auth': add AuthConfig (and ContentTypesConfig) to INSTALLED_APPS.\",\n )\n }\n }\n}\n","// Generated by Ghuri makemigrations: every migration of this app, in order. Do not edit.\nimport m0001_initial from './0001_initial'\n\nexport { m0001_initial }\n\n/** Every migration of this app by name, in order. */\nexport const migrations = {\n '0001_initial': m0001_initial,\n}\n","// Generated by Ghuri makemigrations on 2026-11-12 08:37\nimport { Migration, operations as ops } from '@ghuri/orm/migrations'\n\nexport default new Migration({\n initial: true,\n dependencies: [['auth', '0001_initial']],\n operations: [\n ops.CreateModel({\n name: 'SocialAccount',\n fields: {\n id: { type: 'BigAutoField', primaryKey: true },\n user: {\n type: 'ForeignKey',\n to: 'auth.User',\n onDelete: 'CASCADE',\n dbIndex: true,\n relatedName: 'socialAccounts',\n verboseName: 'user',\n },\n provider: { type: 'CharField', maxLength: 200, verboseName: 'provider' },\n uid: { type: 'CharField', maxLength: 191, verboseName: 'uid' },\n lastLogin: { type: 'DateTimeField', autoNow: true, verboseName: 'last login' },\n dateJoined: { type: 'DateTimeField', autoNowAdd: true, verboseName: 'date joined' },\n extraData: {\n type: 'JSONField',\n default: { callable: 'emptyDict' },\n verboseName: 'extra data',\n },\n },\n options: {\n dbTable: 'socialaccount_socialaccount',\n verboseName: 'social account',\n verboseNamePlural: 'social accounts',\n uniqueTogether: [['provider', 'uid']],\n },\n }),\n ops.CreateModel({\n name: 'SocialApp',\n fields: {\n id: { type: 'BigAutoField', primaryKey: true },\n provider: { type: 'CharField', maxLength: 30, verboseName: 'provider' },\n providerId: { type: 'CharField', maxLength: 200, blank: true, verboseName: 'provider ID' },\n name: { type: 'CharField', maxLength: 40, verboseName: 'name' },\n clientId: { type: 'CharField', maxLength: 191, verboseName: 'client id' },\n secret: { type: 'CharField', maxLength: 191, blank: true, verboseName: 'secret key' },\n key: { type: 'CharField', maxLength: 191, blank: true, verboseName: 'key' },\n settings: {\n type: 'JSONField',\n blank: true,\n default: { callable: 'emptyDict' },\n verboseName: 'settings',\n },\n },\n options: {\n dbTable: 'socialaccount_socialapp',\n verboseName: 'social application',\n verboseNamePlural: 'social applications',\n },\n }),\n ops.CreateModel({\n name: 'SocialToken',\n fields: {\n id: { type: 'BigAutoField', primaryKey: true },\n app: {\n type: 'ForeignKey',\n to: 'socialaccount.SocialApp',\n onDelete: 'CASCADE',\n null: true,\n blank: true,\n dbIndex: true,\n },\n account: {\n type: 'ForeignKey',\n to: 'socialaccount.SocialAccount',\n onDelete: 'CASCADE',\n dbIndex: true,\n relatedName: 'tokens',\n },\n token: { type: 'TextField', verboseName: 'token' },\n tokenSecret: { type: 'TextField', blank: true, verboseName: 'token secret' },\n expiresAt: { type: 'DateTimeField', null: true, blank: true, verboseName: 'expires at' },\n },\n options: {\n dbTable: 'socialaccount_socialtoken',\n verboseName: 'social application token',\n verboseNamePlural: 'social application tokens',\n uniqueTogether: [['app', 'account']],\n },\n }),\n ],\n})\n","// What happens after the provider answered: find or link the account, sign up, log in, respond.\nimport { login as authLogin, getUserModel, isSafeRedirect, tokenPairForUser } from '@ghuri/auth'\nimport { cache, getHost, getUser, isSecure, resolveUrl, reverse, tryGetContext } from '@ghuri/core'\nimport {\n loginBackendName,\n type OAuthTokens,\n type Profile,\n randomToken,\n seal,\n unseal,\n userInfo,\n} from '@ghuri/oauth'\nimport type { Context } from 'hono'\nimport { deleteCookie, getCookie, setCookie } from 'hono/cookie'\nimport { getAdapter, type SignupData } from './adapter'\nimport { SocialAccount } from './models'\nimport type { ResolvedProvider } from './resolve'\nimport { socialSettings } from './settings'\nimport { preSocialLogin, socialAccountAdded, socialAccountUpdated } from './signals'\nimport { storeTokens } from './tokens'\n\nexport type Process = 'login' | 'connect'\n/** `browser`: redirects (the OAuth callback); `api`: JSON (native tokens, SPA calls). */\nexport type Mode = 'browser' | 'api'\n\nexport interface SocialLogin extends ResolvedProvider {\n profile: Profile\n tokens?: OAuthTokens\n /** Whether the provider vouches for `profile.email`. */\n emailVerified: boolean\n process: Process\n next?: string\n}\n\nexport class SocialAuthError extends Error {\n constructor(\n message: string,\n readonly status = 400,\n readonly code = 'social_login_failed',\n ) {\n super(message)\n }\n}\n\nexport function buildLogin(\n resolved: ResolvedProvider,\n profile: Profile,\n opts: { tokens?: OAuthTokens; process?: Process; next?: string },\n): SocialLogin {\n return {\n ...resolved,\n profile: { ...profile, provider: resolved.key },\n tokens: opts.tokens,\n emailVerified: resolved.provider.emailVerified(profile, resolved.settings),\n process: opts.process ?? 'login',\n next: opts.next,\n }\n}\n\n// ---- responses ----\n\nfunction loginRedirectUrl(): string {\n return resolveUrl(\n (tryGetContext()?.settings.LOGIN_REDIRECT_URL as string | undefined) ?? '/accounts/profile/',\n )\n}\n\nconst CODE_PURPOSE = 'socialauth-code'\nconst CODE_TTL = 60\n\n/** A one-time code an SPA exchanges for a JWT pair at `token/` (tokens never travel in URLs). */\nexport async function makeLoginCode(user: any): Promise<string> {\n return seal(\n JSON.stringify({\n uid: String(user.pk),\n exp: Math.floor(Date.now() / 1000) + CODE_TTL,\n jti: randomToken(12),\n }),\n CODE_PURPOSE,\n )\n}\n\n/** The user of a login code, once (replays are refused while the cache remembers the code). */\nexport async function redeemLoginCode(code: string): Promise<any | null> {\n const raw = await unseal(code, CODE_PURPOSE)\n if (!raw) return null\n let data: { uid: string; exp: number; jti: string }\n try {\n data = JSON.parse(raw)\n } catch {\n return null\n }\n if (!data.exp || data.exp < Date.now() / 1000) return null\n const key = `ghuri:socialauth:code:${data.jti}`\n try {\n if (await cache.get(key)) return null\n await cache.set(key, 1, CODE_TTL * 2)\n } catch {\n // no cache configured: the 60-second expiry is the only replay limit\n }\n const User = getUserModel()\n const user = await User.objects.filter({ pk: User._meta.pk.toPython(data.uid) } as any).first()\n return user && (user as any).isActive !== false ? user : null\n}\n\n/** Log the user in and answer for the mode and `LOGIN_RESPONSE`. */\nexport async function finishLogin(c: Context, user: any, login: SocialLogin, mode: Mode): Promise<Response> {\n const s = socialSettings()\n if (user.isActive === false) throw new SocialAuthError('This account is inactive.', 403, 'inactive')\n if (s.loginResponse === 'jwt') {\n if (mode === 'api') return c.json({ ...(await tokenPairForUser(user)), user: userInfo(user) })\n if (!s.frontendUrl)\n throw new SocialAuthError('SOCIALACCOUNT.FRONTEND_URL is required with LOGIN_RESPONSE \"jwt\".', 500)\n return c.redirect(`${s.frontendUrl}#code=${encodeURIComponent(await makeLoginCode(user))}`, 302)\n }\n await authLogin(c, user, loginBackendName())\n if (mode === 'api') return c.json({ user: userInfo(user) })\n const next = login.next\n return c.redirect(isSafeRedirect(next, [getHost(c)]) ? next : loginRedirectUrl(), 302)\n}\n\n/** An error, answered as JSON (api) or a redirect to `LOGIN_ERROR_URL` / the frontend (browser). */\nexport async function errorResponse(\n c: Context,\n err: SocialAuthError,\n provider: string,\n mode: Mode,\n): Promise<Response> {\n const custom = await getAdapter().authenticationError(c, { provider, message: err.message, code: err.code })\n if (custom) return custom\n if (mode === 'api') return c.json({ detail: err.message, code: err.code }, err.status as 400)\n const s = socialSettings()\n if (s.loginResponse === 'jwt' && s.frontendUrl) {\n return c.redirect(`${s.frontendUrl}#error=${encodeURIComponent(err.message)}`, 302)\n }\n const url = new URL(s.loginErrorUrl, 'http://x')\n url.searchParams.set('error', err.message)\n return c.redirect(`${url.pathname}${url.search}`, 302)\n}\n\n// ---- pending signup (when the form is needed) ----\n\nconst SIGNUP_COOKIE = 'ghuri_social_signup'\nconst SIGNUP_PURPOSE = 'socialauth-signup'\nconst SIGNUP_TTL = 600\n\nexport interface PendingSignup {\n key: string\n profile: Profile\n tokens?: OAuthTokens\n emailVerified: boolean\n next?: string\n createdAt: number\n}\n\nexport async function savePendingSignup(c: Context, login: SocialLogin): Promise<void> {\n const pending: PendingSignup = {\n key: login.key,\n profile: login.profile,\n tokens: socialSettings().storeTokens ? login.tokens : undefined,\n emailVerified: login.emailVerified,\n next: login.next,\n createdAt: Date.now(),\n }\n setCookie(c, SIGNUP_COOKIE, await seal(JSON.stringify(pending), SIGNUP_PURPOSE), {\n path: '/',\n httpOnly: true,\n secure: isSecure(c),\n sameSite: 'Lax',\n maxAge: SIGNUP_TTL,\n })\n}\n\nexport async function readPendingSignup(c: Context): Promise<PendingSignup | null> {\n const raw = getCookie(c, SIGNUP_COOKIE)\n if (!raw) return null\n const json = await unseal(raw, SIGNUP_PURPOSE)\n if (!json) return null\n try {\n const p = JSON.parse(json) as PendingSignup\n return Date.now() - p.createdAt <= SIGNUP_TTL * 1000 ? p : null\n } catch {\n return null\n }\n}\n\nexport function clearPendingSignup(c: Context): void {\n deleteCookie(c, SIGNUP_COOKIE, { path: '/', secure: isSecure(c) })\n}\n\n/** Expire the pending-signup cookie on a response that was already built. */\nexport function expirePendingSignup(c: Context, res: Response): Response {\n res.headers.append(\n 'set-cookie',\n `${SIGNUP_COOKIE}=; Max-Age=0; Path=/; HttpOnly; SameSite=Lax${isSecure(c) ? '; Secure' : ''}`,\n )\n return res\n}\n\n// ---- the flow ----\n\nasync function emailTaken(email: string, exceptPk?: unknown): Promise<boolean> {\n const User = getUserModel()\n let qs = User.objects.filter({ [`${User.EMAIL_FIELD}__iexact`]: email } as any)\n if (exceptPk !== undefined) qs = qs.exclude({ pk: exceptPk } as any)\n return qs.exists()\n}\n\nasync function link(c: Context, login: SocialLogin, user: any): Promise<SocialAccount> {\n const account = await SocialAccount.objects.create({\n user,\n provider: login.key,\n uid: login.profile.id,\n extraData: login.profile.raw,\n } as any)\n await storeTokens(login, account)\n await socialAccountAdded.send(SocialAccount, { c, login, account })\n return account\n}\n\n/**\n * Create the user from the profile and the (optional) form data, link it, log in. Returns the problems instead\n * when the data is not acceptable.\n */\nexport async function signup(\n c: Context,\n login: SocialLogin,\n data: SignupData,\n mode: Mode,\n): Promise<Response | Record<string, string[]>> {\n const adapter = getAdapter()\n const User = getUserModel()\n const errors: Record<string, string[]> = {}\n const username = (data.username ?? '').trim()\n const email = (data.email ?? '').trim()\n if (User.USERNAME_FIELD !== User.EMAIL_FIELD) {\n if (!username) errors[User.USERNAME_FIELD] = ['This field is required.']\n else if (await User.objects.filter({ [`${User.USERNAME_FIELD}__iexact`]: username } as any).exists()) {\n errors[User.USERNAME_FIELD] = ['A user with that username already exists.']\n }\n }\n if (!email && (socialSettings().emailRequired || User.USERNAME_FIELD === User.EMAIL_FIELD)) {\n errors[User.EMAIL_FIELD] = ['This field is required.']\n } else if (email && (await emailTaken(email))) {\n errors[User.EMAIL_FIELD] = [\n `An account already uses this address. Log in to it first, then connect ${login.provider.name} from your account.`,\n ]\n }\n if (Object.keys(errors).length) return errors\n let user = adapter.newUser(c, login)\n user = adapter.populateUser(c, login, user, {\n username: User.USERNAME_FIELD === User.EMAIL_FIELD ? email : username,\n email: email || undefined,\n })\n user = await adapter.saveUser(c, login, user)\n await link(c, login, user)\n return finishLogin(c, user, login, mode)\n}\n\n/** Process a successful provider login (django-allauth's `complete_social_login`). */\nexport async function completeSocialLogin(c: Context, login: SocialLogin, mode: Mode): Promise<Response> {\n const adapter = getAdapter()\n await preSocialLogin.send(SocialAccount, { c, login })\n await adapter.preSocialLogin(c, login)\n const current = getUser(c)\n const User = getUserModel()\n\n // 1. A known link.\n const existing = await SocialAccount.objects.filter({ provider: login.key, uid: login.profile.id }).first()\n if (existing) {\n existing.extraData = login.profile.raw\n await existing.save()\n await storeTokens(login, existing)\n await socialAccountUpdated.send(SocialAccount, { c, login, account: existing })\n const userId = (existing as any).userId ?? (existing as any).user_id\n if (login.process === 'connect') {\n if (!current.isAuthenticated)\n throw new SocialAuthError('Log in before connecting an account.', 401, 'login_required')\n if (String(userId) !== String(current.pk)) {\n throw new SocialAuthError(\n `This ${login.provider.name} account is already connected to another user.`,\n 409,\n 'already_connected',\n )\n }\n return mode === 'api'\n ? c.json({ connected: true })\n : c.redirect(adapter.getConnectRedirectUrl(c, existing), 302)\n }\n const user = await User.objects.filter({ pk: userId } as any).first()\n if (!user) throw new SocialAuthError('The linked user no longer exists.', 401, 'user_missing')\n return finishLogin(c, user, login, mode)\n }\n\n // 2. Connecting to the logged-in user.\n if (login.process === 'connect') {\n if (!current.isAuthenticated)\n throw new SocialAuthError('Log in before connecting an account.', 401, 'login_required')\n const user = await User.objects.filter({ pk: current.pk } as any).first()\n const account = await link(c, login, user)\n return mode === 'api'\n ? c.json({ connected: true })\n : c.redirect(adapter.getConnectRedirectUrl(c, account), 302)\n }\n\n // 3. A verified email that belongs to exactly one user.\n const s = socialSettings()\n if (s.emailAuthentication && login.emailVerified && login.profile.email) {\n const matches = await User.objects\n .filter({ [`${User.EMAIL_FIELD}__iexact`]: login.profile.email } as any)\n .limit(2)\n if (matches.length === 1) {\n await link(c, login, matches[0])\n return finishLogin(c, matches[0], login, mode)\n }\n }\n\n // 4. Sign up.\n if (!(await adapter.isOpenForSignup(c, login))) {\n throw new SocialAuthError('Sign-ups are closed.', 403, 'signup_closed')\n }\n if (await adapter.isAutoSignupAllowed(c, login)) {\n const email =\n login.profile.email && !(await emailTaken(login.profile.email)) ? login.profile.email : undefined\n if (email || (!s.emailRequired && !login.profile.email && User.USERNAME_FIELD !== User.EMAIL_FIELD)) {\n const result = await signup(\n c,\n login,\n {\n username:\n User.USERNAME_FIELD === User.EMAIL_FIELD ? email : await adapter.generateUsername(c, login),\n email,\n },\n mode,\n )\n if (result instanceof Response) return result\n }\n }\n await savePendingSignup(c, login)\n let signupUrl = '/accounts/signup/'\n try {\n signupUrl = reverse('socialaccount_signup')\n } catch {\n // not routed by name\n }\n if (mode === 'api') {\n return c.json({ detail: 'Finish signing up.', code: 'signup_required', signupUrl }, 409)\n }\n return c.redirect(signupUrl, 302)\n}\n","import { Signal } from '@ghuri/core'\nimport type { Context } from 'hono'\nimport type { SocialLogin } from './login'\nimport type { SocialAccount } from './models'\n\nconst g = globalThis as any\nfunction singleton<T>(key: string, make: () => T): T {\n const k = Symbol.for(key)\n if (!g[k]) g[k] = make()\n return g[k]\n}\n\n/** Before a social login is processed (after the provider answered). */\nexport const preSocialLogin: Signal<{ c: Context; login: SocialLogin }> = singleton(\n 'ghuri.socialauth.preSocialLogin',\n () => new Signal('preSocialLogin'),\n)\n/** A provider account was linked to a user (signup or connect). */\nexport const socialAccountAdded: Signal<{ c: Context; login: SocialLogin; account: SocialAccount }> =\n singleton('ghuri.socialauth.socialAccountAdded', () => new Signal('socialAccountAdded'))\n/** An existing link logged in again (profile and tokens refreshed). */\nexport const socialAccountUpdated: Signal<{ c: Context; login: SocialLogin; account: SocialAccount }> =\n singleton('ghuri.socialauth.socialAccountUpdated', () => new Signal('socialAccountUpdated'))\n/** A link was removed from the connections page. */\nexport const socialAccountRemoved: Signal<{ c: Context; account: SocialAccount }> = singleton(\n 'ghuri.socialauth.socialAccountRemoved',\n () => new Signal('socialAccountRemoved'),\n)\n","// Provider tokens (STORE_TOKENS), encrypted at rest with a key derived from SECRET_KEY.\nimport { OAuth2Strategy, type OAuthTokens, seal, unseal } from '@ghuri/oauth'\nimport type { SocialLogin } from './login'\nimport { type SocialAccount, SocialToken } from './models'\nimport { resolveProvider } from './resolve'\nimport { socialSettings } from './settings'\n\nconst PURPOSE = 'socialauth-token'\n\nexport async function storeTokens(login: SocialLogin, account: SocialAccount): Promise<void> {\n if (!socialSettings().storeTokens || !login.tokens?.accessToken) return\n const t = login.tokens\n const app = login.row ?? null\n const existing = await SocialToken.objects.filter({ account, app } as any).first()\n const values = {\n token: await seal(t.accessToken, PURPOSE),\n tokenSecret: t.refreshToken ? await seal(t.refreshToken, PURPOSE) : (existing?.tokenSecret ?? ''),\n expiresAt: t.expiresAt ? new Date(t.expiresAt) : null,\n }\n if (existing) {\n Object.assign(existing, values)\n await existing.save()\n } else {\n await SocialToken.objects.create({ account, app, ...values } as any)\n }\n}\n\n/**\n * A usable access token for the account (refreshed with the stored refresh token when it expired), or null\n * when tokens are not stored or cannot be refreshed.\n */\nexport async function getAccessToken(account: SocialAccount): Promise<string | null> {\n const row = await SocialToken.objects.filter({ account } as any).first()\n if (!row) return null\n const access = await unseal(row.token, PURPOSE)\n const expiresAt = row.expiresAt ? new Date(row.expiresAt as any).getTime() : undefined\n if (access && (!expiresAt || expiresAt - 30_000 > Date.now())) return access\n const refresh = row.tokenSecret ? await unseal(row.tokenSecret, PURPOSE) : null\n if (!refresh) return null\n const resolved = await resolveProvider(account.provider)\n if (!resolved) return null\n const strategy = resolved.provider.createStrategy({\n key: resolved.key,\n app: resolved.app,\n settings: resolved.settings,\n callbackURL: '/',\n verify: async () => null,\n })\n if (!(strategy instanceof OAuth2Strategy)) return null\n let tokens: OAuthTokens\n try {\n tokens = await (await strategy.client()).refresh(refresh)\n } catch {\n return null\n }\n row.token = await seal(tokens.accessToken, PURPOSE)\n if (tokens.refreshToken) row.tokenSecret = await seal(tokens.refreshToken, PURPOSE)\n row.expiresAt = (tokens.expiresAt ? new Date(tokens.expiresAt) : null) as any\n await row.save()\n return tokens.accessToken\n}\n","// The provider catalog: each provider turns app credentials into an @ghuri/oauth strategy and knows how far to\n// trust its profile (is the email verified?).\n\nimport { ImproperlyConfigured } from '@ghuri/core'\nimport {\n getJson,\n OAuth2Strategy,\n OAuthError,\n OIDCStrategy,\n type Profile,\n profileFromClaims,\n providerFetch,\n readBody,\n type VerifyFunction,\n} from '@ghuri/oauth'\nimport type { AppSettings, ProviderSettings } from './settings'\n\nexport interface StrategyContext {\n /** The id used in URLs and stored on `SocialAccount.provider` (`github`, or an OIDC app's `providerId`). */\n key: string\n app: AppSettings\n settings: ProviderSettings\n callbackURL: string\n verify: VerifyFunction\n}\n\nexport abstract class Provider {\n abstract readonly id: string\n abstract readonly name: string\n /** Several apps per provider, each with its own `providerId` (OpenID Connect). */\n readonly multipleApps: boolean = false\n /** Default scopes when `SCOPE` is not set. */\n readonly defaultScope: string[] = []\n\n abstract createStrategy(ctx: StrategyContext): OAuth2Strategy\n\n scope(settings: ProviderSettings): string[] {\n return settings.SCOPE ?? this.defaultScope\n }\n\n /** May this provider's email be trusted to belong to the user? */\n emailVerified(profile: Profile, settings: ProviderSettings): boolean {\n if (settings.VERIFIED_EMAIL !== undefined) return settings.VERIFIED_EMAIL && !!profile.email\n return profile.emailVerified === true && !!profile.email\n }\n\n /**\n * Native / mobile login: verify a token the app obtained with the provider's own SDK and return the profile.\n * The token must have been issued to one of our client ids. Default: ID tokens of OpenID Connect providers.\n */\n async verifyNativeToken(\n ctx: StrategyContext,\n tokens: { accessToken?: string; idToken?: string },\n ): Promise<Profile> {\n const strategy = this.createStrategy(ctx)\n if (!(strategy instanceof OIDCStrategy) || !tokens.idToken) {\n throw new OAuthError(`${this.name} login with a native token needs an id_token.`, 'unsupported')\n }\n const audiences = [ctx.app.clientId, ...((ctx.app.settings?.audiences as string[] | undefined) ?? [])]\n let claims: Record<string, any> | undefined\n let lastError: unknown\n for (const aud of audiences) {\n try {\n const s = this.createStrategy({ ...ctx, app: { ...ctx.app, clientId: aud } }) as OIDCStrategy\n claims = await s.validateIdToken(tokens.idToken)\n break\n } catch (err) {\n lastError = err\n }\n }\n if (!claims)\n throw lastError instanceof Error\n ? new OAuthError(lastError.message, 'invalid_token')\n : new OAuthError('Invalid ID token.')\n return this.profileFromClaims(ctx.key, claims)\n }\n\n profileFromClaims(key: string, claims: Record<string, any>): Profile {\n return profileFromClaims(key, claims)\n }\n}\n\nfunction common(ctx: StrategyContext, provider: Provider) {\n return {\n name: ctx.key,\n clientId: ctx.app.clientId,\n clientSecret: ctx.app.secret,\n callbackURL: ctx.callbackURL,\n scope: provider.scope(ctx.settings),\n authorizationParams: ctx.settings.AUTH_PARAMS,\n }\n}\n\n/** An OIDC strategy whose profile goes through the provider's own claim mapping. */\nfunction oidc(\n ctx: StrategyContext,\n provider: Provider,\n issuer: string,\n extra: Record<string, unknown> = {},\n): OIDCStrategy {\n return new OIDCStrategy(\n {\n ...common(ctx, provider),\n issuer,\n profile: async (tokens) =>\n provider.profileFromClaims(ctx.key, (tokens.raw as { claims: Record<string, any> }).claims),\n ...extra,\n },\n ctx.verify,\n )\n}\n\n// ---- GitHub ----\n\nexport class GitHubProvider extends Provider {\n readonly id = 'github'\n readonly name = 'GitHub'\n override readonly defaultScope = ['read:user', 'user:email']\n\n private api(ctx: StrategyContext): string {\n return String(ctx.app.settings?.apiUrl ?? 'https://api.github.com').replace(/\\/+$/, '')\n }\n\n createStrategy(ctx: StrategyContext): OAuth2Strategy {\n const web = String(ctx.app.settings?.webUrl ?? 'https://github.com').replace(/\\/+$/, '')\n const api = this.api(ctx)\n return new OAuth2Strategy(\n {\n ...common(ctx, this),\n authorizationURL: `${web}/login/oauth/authorize`,\n tokenURL: `${web}/login/oauth/access_token`,\n profile: async (_tokens, p) => this.profile(ctx.key, api, (url) => p.getJsonAuthed(url)),\n },\n ctx.verify,\n )\n }\n\n private async profile(key: string, api: string, get: (url: string) => Promise<any>): Promise<Profile> {\n const user = await get(`${api}/user`)\n let email: string | undefined = user.email ?? undefined\n let verified = false\n try {\n const emails = (await get(`${api}/user/emails`)) as unknown as Array<{\n email: string\n primary: boolean\n verified: boolean\n }>\n const list = Array.isArray(emails) ? emails : []\n const primary = list.find((e) => e.primary && e.verified) ?? list.find((e) => e.verified)\n if (primary) {\n email = primary.email\n verified = true\n }\n } catch {\n // no user:email scope\n }\n return {\n provider: key,\n id: String(user.id),\n username: user.login,\n name: user.name ?? undefined,\n email,\n emailVerified: verified,\n avatarUrl: user.avatar_url,\n raw: user,\n }\n }\n\n /** Checks with GitHub that the token belongs to our OAuth app (`POST /applications/{client_id}/token`). */\n override async verifyNativeToken(ctx: StrategyContext, tokens: { accessToken?: string }): Promise<Profile> {\n if (!tokens.accessToken)\n throw new OAuthError('GitHub login with a native token needs an access_token.', 'unsupported')\n const api = this.api(ctx)\n const res = await providerFetch(`${api}/applications/${encodeURIComponent(ctx.app.clientId)}/token`, {\n method: 'POST',\n headers: {\n authorization: `Basic ${btoa(`${ctx.app.clientId}:${ctx.app.secret ?? ''}`)}`,\n accept: 'application/vnd.github+json',\n 'content-type': 'application/json',\n },\n body: JSON.stringify({ access_token: tokens.accessToken }),\n })\n if (!res.ok) throw new OAuthError('GitHub did not accept the access token for this app.', 'invalid_token')\n const headers = { authorization: `Bearer ${tokens.accessToken}` }\n return this.profile(ctx.key, api, (url) => getJson(url, { headers }))\n }\n}\n\n// ---- Google ----\n\nexport class GoogleProvider extends Provider {\n readonly id = 'google'\n readonly name = 'Google'\n override readonly defaultScope = ['openid', 'email', 'profile']\n\n createStrategy(ctx: StrategyContext): OAuth2Strategy {\n return oidc(ctx, this, 'https://accounts.google.com')\n }\n}\n\n// ---- Facebook ----\n\nexport class FacebookProvider extends Provider {\n readonly id = 'facebook'\n readonly name = 'Facebook'\n override readonly defaultScope = ['email', 'public_profile']\n\n private graph(ctx: StrategyContext): string {\n return `https://graph.facebook.com/${String(ctx.settings.VERSION ?? ctx.app.settings?.version ?? 'v21.0')}`\n }\n\n createStrategy(ctx: StrategyContext): OAuth2Strategy {\n const version = String(ctx.settings.VERSION ?? ctx.app.settings?.version ?? 'v21.0')\n const graph = this.graph(ctx)\n return new OAuth2Strategy(\n {\n ...common(ctx, this),\n scopeSeparator: ',',\n authorizationURL: `https://www.facebook.com/${version}/dialog/oauth`,\n tokenURL: `${graph}/oauth/access_token`,\n profile: async (_t, p) =>\n this.profile(\n ctx.key,\n await p.getJsonAuthed(`${graph}/me?fields=id,name,email,first_name,last_name,picture`),\n ),\n },\n ctx.verify,\n )\n }\n\n private profile(key: string, me: Record<string, any>): Profile {\n return {\n provider: key,\n id: String(me.id),\n name: me.name,\n firstName: me.first_name,\n lastName: me.last_name,\n email: me.email,\n // Facebook does not say whether the address was confirmed: unverified unless VERIFIED_EMAIL.\n emailVerified: false,\n avatarUrl: me.picture?.data?.url,\n raw: me,\n }\n }\n\n /** Checks the token with `debug_token` (issued to our app id) before trusting it. */\n override async verifyNativeToken(ctx: StrategyContext, tokens: { accessToken?: string }): Promise<Profile> {\n if (!tokens.accessToken)\n throw new OAuthError('Facebook login with a native token needs an access_token.', 'unsupported')\n const graph = this.graph(ctx)\n const appToken = `${ctx.app.clientId}|${ctx.app.secret ?? ''}`\n const debug = await getJson(\n `${graph}/debug_token?input_token=${encodeURIComponent(tokens.accessToken)}&access_token=${encodeURIComponent(appToken)}`,\n )\n if (!debug.data?.is_valid || String(debug.data.app_id) !== ctx.app.clientId) {\n throw new OAuthError('The Facebook token was not issued to this app.', 'invalid_token')\n }\n const me = await getJson(`${graph}/me?fields=id,name,email,first_name,last_name,picture`, {\n headers: { authorization: `Bearer ${tokens.accessToken}` },\n })\n return this.profile(ctx.key, me)\n }\n}\n\n// ---- Microsoft (Entra ID) ----\n\nexport class MicrosoftProvider extends Provider {\n readonly id = 'microsoft'\n readonly name = 'Microsoft'\n override readonly defaultScope = ['openid', 'email', 'profile', 'User.Read']\n\n createStrategy(ctx: StrategyContext): OAuth2Strategy {\n const tenant = String(ctx.app.settings?.tenant ?? ctx.settings.TENANT ?? 'common')\n const multi = ['common', 'organizations', 'consumers'].includes(tenant)\n return oidc(ctx, this, `https://login.microsoftonline.com/${tenant}/v2.0`, {\n // Multi-tenant endpoints publish `{tenantid}` in their issuer; accept any tenant's issuer.\n issuerValidation: multi\n ? (iss: string) => /^https:\\/\\/login\\.microsoftonline\\.com\\/[0-9a-f-]{36}\\/v2\\.0$/.test(iss)\n : undefined,\n fetchUserInfo: false,\n })\n }\n\n override profileFromClaims(key: string, claims: Record<string, any>): Profile {\n const p = profileFromClaims(key, claims)\n // Entra ID emails are not verified by Microsoft (tenants can set any address): never trust them by default.\n return { ...p, id: String(claims.oid ?? claims.sub), emailVerified: false }\n }\n\n override emailVerified(profile: Profile, settings: ProviderSettings): boolean {\n return settings.VERIFIED_EMAIL === true && !!profile.email\n }\n}\n\n// ---- Discord ----\n\nexport class DiscordProvider extends Provider {\n readonly id = 'discord'\n readonly name = 'Discord'\n override readonly defaultScope = ['identify', 'email']\n\n createStrategy(ctx: StrategyContext): OAuth2Strategy {\n return new OAuth2Strategy(\n {\n ...common(ctx, this),\n authorizationURL: 'https://discord.com/oauth2/authorize',\n tokenURL: 'https://discord.com/api/oauth2/token',\n profile: async (_t, p) => {\n const me = await p.getJsonAuthed('https://discord.com/api/users/@me')\n return {\n provider: ctx.key,\n id: String(me.id),\n username: me.username,\n name: me.global_name ?? me.username,\n email: me.email ?? undefined,\n emailVerified: me.verified === true,\n avatarUrl: me.avatar ? `https://cdn.discordapp.com/avatars/${me.id}/${me.avatar}.png` : undefined,\n raw: me,\n }\n },\n },\n ctx.verify,\n )\n }\n\n override async verifyNativeToken(): Promise<Profile> {\n throw new OAuthError(\n 'Discord tokens cannot be checked against a client id; use the redirect flow.',\n 'unsupported',\n )\n }\n}\n\n// ---- GitLab (gitlab.com or self-hosted) ----\n\nexport class GitLabProvider extends Provider {\n readonly id = 'gitlab'\n readonly name = 'GitLab'\n override readonly defaultScope = ['openid', 'email', 'profile']\n\n createStrategy(ctx: StrategyContext): OAuth2Strategy {\n const url = String(ctx.app.settings?.url ?? ctx.settings.GITLAB_URL ?? 'https://gitlab.com').replace(\n /\\/+$/,\n '',\n )\n return oidc(ctx, this, url)\n }\n\n override profileFromClaims(key: string, claims: Record<string, any>): Profile {\n return { ...profileFromClaims(key, claims), username: claims.nickname ?? claims.preferred_username }\n }\n}\n\n// ---- Any OpenID Connect issuer ----\n\nexport class OpenIDConnectProvider extends Provider {\n readonly id = 'openid_connect'\n readonly name = 'OpenID Connect'\n override readonly multipleApps = true\n override readonly defaultScope = ['openid', 'email', 'profile']\n\n createStrategy(ctx: StrategyContext): OAuth2Strategy {\n const issuer = ctx.app.settings?.serverUrl ?? ctx.app.settings?.server_url\n if (typeof issuer !== 'string') {\n throw new ImproperlyConfigured(\n `The OpenID Connect app '${ctx.key}' needs settings.serverUrl (the issuer).`,\n )\n }\n return oidc(ctx, this, issuer)\n }\n}\n\n// ---- registry ----\n\nconst KEY = Symbol.for('ghuri.socialauth.providers')\nconst registry: Map<string, Provider> = (() => {\n const g = globalThis as any\n if (!g[KEY]) {\n const m = new Map<string, Provider>()\n for (const p of [\n new GitHubProvider(),\n new GoogleProvider(),\n new FacebookProvider(),\n new MicrosoftProvider(),\n new DiscordProvider(),\n new GitLabProvider(),\n new OpenIDConnectProvider(),\n ]) {\n m.set(p.id, p)\n }\n g[KEY] = m\n }\n return g[KEY]\n})()\n\n/** Add (or replace) a provider: `registerProvider(new MyProvider())`. */\nexport function registerProvider(provider: Provider): void {\n registry.set(provider.id, provider)\n}\n\nexport function getProvider(id: string): Provider | undefined {\n return registry.get(id)\n}\n\nexport function allProviders(): Provider[] {\n return [...registry.values()]\n}\n\n/** Used by provider subclasses that need raw responses. */\nexport { readBody }\n","// Which providers are configured, and with which app credentials (settings first, then SocialApp rows).\n\nimport { SocialApp } from './models'\nimport { allProviders, getProvider, type Provider } from './providers'\nimport { type AppSettings, type ProviderSettings, socialSettings } from './settings'\n\nexport interface ResolvedProvider {\n /** The id in URLs and on `SocialAccount.provider`. */\n key: string\n provider: Provider\n app: AppSettings\n settings: ProviderSettings\n /** The `SocialApp` row, when the credentials came from the database. */\n row?: SocialApp\n}\n\nfunction fromRow(row: SocialApp): AppSettings {\n return {\n clientId: row.clientId,\n secret: row.secret || undefined,\n key: row.key || undefined,\n providerId: row.providerId || undefined,\n name: row.name,\n settings: (row.settings as Record<string, unknown>) ?? {},\n }\n}\n\nasync function safeRows(filter: Record<string, unknown>): Promise<SocialApp[]> {\n try {\n return await SocialApp.objects.filter(filter).orderBy('id')\n } catch {\n return [] // table not migrated yet\n }\n}\n\n/** The provider for `key` (`github`, or the `providerId` of a multi-app provider), or null if not configured. */\nexport async function resolveProvider(key: string): Promise<ResolvedProvider | null> {\n const all = socialSettings().providers\n const direct = getProvider(key)\n if (direct && !direct.multipleApps) {\n const settings = all[key] ?? {}\n if (settings.APP) return { key, provider: direct, app: settings.APP, settings }\n const [row] = await safeRows({ provider: key })\n return row ? { key, provider: direct, app: fromRow(row), settings, row } : null\n }\n for (const provider of allProviders().filter((p) => p.multipleApps)) {\n const settings = all[provider.id] ?? {}\n const app = settings.APPS?.find((a) => a.providerId === key)\n if (app) return { key, provider, app, settings }\n const [row] = await safeRows({ provider: provider.id, providerId: key })\n if (row) return { key, provider, app: fromRow(row), settings, row }\n }\n return null\n}\n\n/** Every configured provider (for login buttons). */\nexport async function configuredProviders(): Promise<ResolvedProvider[]> {\n const all = socialSettings().providers\n const out: ResolvedProvider[] = []\n const seen = new Set<string>()\n for (const provider of allProviders()) {\n const settings = all[provider.id] ?? {}\n if (provider.multipleApps) {\n for (const app of settings.APPS ?? []) {\n if (app.providerId && !seen.has(app.providerId)) {\n seen.add(app.providerId)\n out.push({ key: app.providerId, provider, app, settings })\n }\n }\n for (const row of await safeRows({ provider: provider.id })) {\n if (row.providerId && !seen.has(row.providerId)) {\n seen.add(row.providerId)\n out.push({ key: row.providerId, provider, app: fromRow(row), settings, row })\n }\n }\n } else if (settings.APP) {\n seen.add(provider.id)\n out.push({ key: provider.id, provider, app: settings.APP, settings })\n }\n }\n for (const row of await safeRows({})) {\n const provider = getProvider(row.provider)\n if (provider && !provider.multipleApps && !seen.has(row.provider)) {\n seen.add(row.provider)\n out.push({ key: row.provider, provider, app: fromRow(row), settings: all[row.provider] ?? {}, row })\n }\n }\n return out\n}\n","// URLs and views: providers list, login start, callback, native tokens, SPA code exchange, signup, connections.\nimport { getUserModel, readData, tokenPairForUser } from '@ghuri/auth'\nimport {\n csrfExempt,\n escapeHtml,\n getCsrfToken,\n getUser,\n path,\n reverse,\n urlpatterns,\n type ViewFunction,\n wantsJson,\n} from '@ghuri/core'\nimport { type OAuthTokens, type Profile, userInfo } from '@ghuri/oauth'\nimport type { Context } from 'hono'\nimport { ImmediateResponse } from './adapter'\nimport {\n buildLogin,\n completeSocialLogin,\n errorResponse,\n expirePendingSignup,\n type Mode,\n type Process,\n readPendingSignup,\n redeemLoginCode,\n SocialAuthError,\n signup,\n} from './login'\nimport { SocialAccount } from './models'\nimport { configuredProviders, type ResolvedProvider, resolveProvider } from './resolve'\nimport { socialSettings } from './settings'\nimport { socialAccountRemoved } from './signals'\n\nfunction page(title: string, body: string, status = 200): Response {\n const html = `<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\"><title>${escapeHtml(title)}</title><style>body{font:16px/1.5 system-ui,sans-serif;max-width:28rem;margin:4rem auto;padding:0 1rem}button{font:inherit;padding:.5rem 1rem;cursor:pointer}input{font:inherit;width:100%;padding:.4rem;margin:.2rem 0 .8rem;box-sizing:border-box}.err{color:#b91c1c}</style></head><body><h1>${escapeHtml(title)}</h1>${body}</body></html>`\n return new Response(html, { status, headers: { 'content-type': 'text/html; charset=utf-8' } })\n}\n\nfunction csrfInput(c: Context): string {\n try {\n return `<input type=\"hidden\" name=\"csrfmiddlewaretoken\" value=\"${escapeHtml(getCsrfToken(c))}\">`\n } catch {\n return ''\n }\n}\n\nfunction str(v: unknown): string | undefined {\n return typeof v === 'string' && v ? v : undefined\n}\n\nasync function provider(c: Context): Promise<ResolvedProvider> {\n const key = c.req.param('provider') ?? ''\n const resolved = await resolveProvider(key)\n if (!resolved)\n throw new SocialAuthError(`Unknown or unconfigured provider '${key}'.`, 404, 'unknown_provider')\n return resolved\n}\n\nfunction strategyFor(c: Context, resolved: ResolvedProvider) {\n const callbackURL = c.req.path.replace(/login\\/(callback\\/)?$/, 'login/callback/')\n const override = (globalThis as any)[Symbol.for('ghuri.socialauth.testStrategy')] as\n | ((key: string, callbackURL: string) => import('@ghuri/oauth').Strategy | undefined)\n | undefined\n const fake = override?.(resolved.key, callbackURL)\n if (fake) return fake\n return resolved.provider.createStrategy({\n key: resolved.key,\n app: resolved.app,\n settings: resolved.settings,\n callbackURL,\n // The social flow decides what happens next; the strategy only has to succeed.\n verify: async () => ({ socialLogin: true }),\n })\n}\n\n/** Run a handler, turning SocialAuthError / ImmediateResponse into responses. */\nfunction guarded(mode: Mode | ((c: Context) => Mode), fn: (c: Context) => Promise<Response>): ViewFunction {\n return async (c) => {\n const m = typeof mode === 'function' ? mode(c) : mode\n try {\n return await fn(c)\n } catch (err) {\n if (err instanceof ImmediateResponse) return err.response\n if (err instanceof SocialAuthError) return errorResponse(c, err, c.req.param('provider') ?? '', m)\n throw err\n }\n }\n}\n\n/** JSON only: refuses cross-site form posts to the CSRF-exempt API endpoints (they can't send JSON). */\nfunction requireJson(c: Context): void {\n if (!(c.req.header('content-type') ?? '').includes('application/json')) {\n throw new SocialAuthError('Send a JSON body (Content-Type: application/json).', 415, 'json_required')\n }\n}\n\n// ---- views ----\n\n/** `GET providers/`: configured providers with their login URLs (for SPA buttons). */\nexport const providersView: ViewFunction = async (c) => {\n const list = await configuredProviders()\n return c.json({\n providers: list.map((p) => ({\n id: p.key,\n name: p.app.name ?? p.provider.name,\n provider: p.provider.id,\n loginUrl: reverse('socialaccount_login', { provider: p.key }),\n nativeTokenUrl: reverse('socialaccount_native_token', { provider: p.key }),\n })),\n })\n}\n\n/** `<provider>/login/`: POST starts the flow; GET confirms first (unless LOGIN_ON_GET). */\nexport const loginView: ViewFunction = guarded('browser', async (c) => {\n const resolved = await provider(c)\n const s = socialSettings()\n if (c.req.method === 'GET' && !s.loginOnGet) {\n if (wantsJson(c)) return c.json({ detail: 'POST to this URL to log in.', method: 'POST' }, 405)\n const action = escapeHtml(c.req.url.replace(/^[a-z]+:\\/\\/[^/]+/i, ''))\n const name = escapeHtml(resolved.app.name ?? resolved.provider.name)\n return page(\n `Continue with ${resolved.app.name ?? resolved.provider.name}`,\n `<p>You are about to log in with ${name}.</p><form method=\"post\" action=\"${action}\">${csrfInput(c)}<button type=\"submit\">Continue</button></form>`,\n )\n }\n if (c.req.method !== 'GET' && c.req.method !== 'POST') return c.text('Method not allowed', 405)\n const data = c.req.method === 'POST' ? await readData(c) : {}\n const process = (str(data.process) ?? c.req.query('process')) === 'connect' ? 'connect' : 'login'\n if (process === 'connect' && !getUser(c).isAuthenticated) {\n throw new SocialAuthError('Log in before connecting an account.', 401, 'login_required')\n }\n const result = await strategyFor(c, resolved).authenticate(c, {\n next: str(data.next) ?? c.req.query('next'),\n state: { process },\n })\n if (result.type === 'redirect') return c.redirect(result.url, 302)\n if (result.type === 'error') throw result.error\n throw new SocialAuthError(\n result.type === 'fail' ? (result.message ?? 'Login failed.') : 'Login failed.',\n 400,\n )\n})\n\n/** `<provider>/login/callback/`: the provider sends the browser back here. */\nexport const callbackView: ViewFunction = guarded('browser', async (c) => {\n const resolved = await provider(c)\n if (!c.req.query('code') && !c.req.query('error')) {\n throw new SocialAuthError('The provider did not send an authorization code.', 400, 'missing_code')\n }\n const result = await strategyFor(c, resolved).authenticate(c, {})\n if (result.type === 'error') throw result.error\n if (result.type !== 'success') {\n throw new SocialAuthError(\n result.type === 'fail' ? (result.message ?? 'Login failed.') : 'Login failed.',\n 401,\n )\n }\n const info = result.info as {\n profile: Profile\n tokens: OAuthTokens\n next?: string\n state?: { process?: Process }\n }\n const login = buildLogin(resolved, info.profile, {\n tokens: info.tokens,\n next: info.next,\n process: info.state?.process === 'connect' ? 'connect' : 'login',\n })\n return completeSocialLogin(c, login, 'browser')\n})\n\n/**\n * `POST <provider>/token/` `{ id_token }` or `{ access_token }`: log in with a token a native app got from the\n * provider's SDK. The token is checked against our client id(s) before it is trusted.\n */\nexport const nativeTokenView: ViewFunction = csrfExempt(\n guarded('api', async (c) => {\n if (c.req.method !== 'POST') return c.json({ detail: 'Method not allowed' }, 405)\n requireJson(c)\n const resolved = await provider(c)\n const body = (await c.req.json().catch(() => ({}))) as Record<string, unknown>\n const idToken = str(body.id_token)\n const accessToken = str(body.access_token)\n if (!idToken && !accessToken)\n throw new SocialAuthError('Send id_token or access_token.', 400, 'missing_token')\n let profile: Profile\n try {\n profile = await resolved.provider.verifyNativeToken(\n {\n key: resolved.key,\n app: resolved.app,\n settings: resolved.settings,\n callbackURL: '/',\n verify: async () => null,\n },\n { idToken, accessToken },\n )\n } catch (err) {\n throw new SocialAuthError((err as Error).message || 'Invalid token.', 401, 'invalid_token')\n }\n const login = buildLogin(resolved, profile, {\n tokens: accessToken ? { accessToken, raw: {} } : undefined,\n process: str(body.process) === 'connect' ? 'connect' : 'login',\n })\n return completeSocialLogin(c, login, 'api')\n }),\n)\n\n/** `POST token/` `{ code }`: exchange the one-time code from an SPA redirect for a JWT pair. */\nexport const tokenExchangeView: ViewFunction = csrfExempt(\n guarded('api', async (c) => {\n if (c.req.method !== 'POST') return c.json({ detail: 'Method not allowed' }, 405)\n requireJson(c)\n const body = (await c.req.json().catch(() => ({}))) as Record<string, unknown>\n const user = str(body.code) ? await redeemLoginCode(str(body.code)!) : null\n if (!user)\n throw new SocialAuthError('This login code is invalid, expired or already used.', 400, 'invalid_code')\n return c.json({ ...(await tokenPairForUser(user)), user: userInfo(user) })\n }),\n)\n\n/** `signup/`: finish a social signup that needs a username or email. */\nexport const signupView: ViewFunction = guarded(\n (c) => (wantsJson(c) ? 'api' : 'browser'),\n async (c) => {\n const pending = await readPendingSignup(c)\n if (!pending)\n throw new SocialAuthError('There is no social signup in progress.', 400, 'no_pending_signup')\n const resolved = await resolveProvider(pending.key)\n if (!resolved) throw new SocialAuthError('The provider is no longer configured.', 400, 'unknown_provider')\n const login = buildLogin(resolved, pending.profile, { tokens: pending.tokens, next: pending.next })\n const User = getUserModel()\n const uf = User.USERNAME_FIELD\n const ef = User.EMAIL_FIELD\n const json = wantsJson(c)\n const render = (values: Record<string, string>, errors: Record<string, string[]> = {}, status = 200) => {\n if (json) {\n return c.json(\n {\n provider: pending.key,\n profile: {\n email: pending.profile.email,\n username: pending.profile.username,\n name: pending.profile.name,\n },\n fields: [...new Set([uf, ef])],\n errors,\n },\n status as 200,\n )\n }\n const field = (name: string, label: string) =>\n `<label>${escapeHtml(label)}<input name=\"${escapeHtml(name)}\" value=\"${escapeHtml(values[name] ?? '')}\"></label>${(errors[name] ?? []).map((e) => `<p class=\"err\">${escapeHtml(e)}</p>`).join('')}`\n const fields = uf === ef ? field(ef, 'Email') : field(uf, 'Username') + field(ef, 'Email')\n return page(\n 'Finish signing up',\n `<p>You are signing up with ${escapeHtml(resolved.app.name ?? resolved.provider.name)}.</p><form method=\"post\">${csrfInput(c)}${fields}<button type=\"submit\">Sign up</button></form>`,\n status,\n )\n }\n if (c.req.method === 'GET') {\n return render({ [uf]: pending.profile.username ?? '', [ef]: pending.profile.email ?? '' })\n }\n const data = await readData(c)\n const values = { [uf]: String(data[uf] ?? ''), [ef]: String(data[ef] ?? '') }\n // An address the user typed is not verified by the provider.\n if (values[ef] && values[ef].toLowerCase() !== (pending.profile.email ?? '').toLowerCase())\n login.emailVerified = false\n const result = await signup(\n c,\n login,\n { username: values[uf], email: values[ef] },\n json ? 'api' : 'browser',\n )\n if (result instanceof Response) return expirePendingSignup(c, result)\n return render(values, result, 400)\n },\n)\n\n/** `connections/`: list the user's social accounts (GET) and disconnect one (POST `{ account }`). */\nexport const connectionsView: ViewFunction = guarded(\n (c) => (wantsJson(c) ? 'api' : 'browser'),\n async (c) => {\n const user = getUser(c)\n if (!user.isAuthenticated)\n throw new SocialAuthError('Log in to manage your connected accounts.', 401, 'login_required')\n const accounts = await SocialAccount.objects.filter({ user: user.pk } as any).orderBy('provider', 'id')\n if (c.req.method === 'POST') {\n const data = await readData(c)\n const id = String(data.account ?? '')\n const account = accounts.find((a) => String(a.pk) === id)\n if (!account) throw new SocialAuthError('No such connected account.', 404, 'not_found')\n const User = getUserModel()\n const full = await User.objects.filter({ pk: user.pk } as any).first()\n if (\n accounts.length === 1 &&\n full &&\n typeof (full as any).hasUsablePassword === 'function' &&\n !(full as any).hasUsablePassword()\n ) {\n throw new SocialAuthError(\n 'Set a password before disconnecting your last connected account.',\n 400,\n 'last_login_method',\n )\n }\n await account.delete()\n await socialAccountRemoved.send(SocialAccount, { c, account })\n if (wantsJson(c)) return c.json({ disconnected: id })\n return c.redirect(c.req.path, 302)\n }\n const list = accounts.map((a) => ({\n id: a.pk,\n provider: a.provider,\n uid: a.uid,\n lastLogin: a.lastLogin,\n dateJoined: a.dateJoined,\n }))\n if (wantsJson(c)) return c.json({ accounts: list })\n const rows = list\n .map(\n (a) =>\n `<li>${escapeHtml(a.provider)} <form method=\"post\" style=\"display:inline\">${csrfInput(c)}<input type=\"hidden\" name=\"account\" value=\"${escapeHtml(a.id)}\"><button type=\"submit\">Disconnect</button></form></li>`,\n )\n .join('')\n return page('Connected accounts', rows ? `<ul>${rows}</ul>` : '<p>No connected accounts.</p>')\n },\n)\n\n/**\n * `path('accounts/', include(socialUrls))` → `providers/`, `token/`, `signup/`, `connections/`,\n * `<provider>/login/`, `<provider>/login/callback/`, `<provider>/token/`.\n */\nexport const socialUrls = urlpatterns(undefined, [\n path('providers/', providersView, { name: 'socialaccount_providers' }),\n path('token/', tokenExchangeView, { name: 'socialaccount_token_exchange' }),\n path('signup/', signupView, { name: 'socialaccount_signup' }),\n path('connections/', connectionsView, { name: 'socialaccount_connections' }),\n path('<str:provider>/login/', loginView, { name: 'socialaccount_login' }),\n path('<str:provider>/login/callback/', callbackView, { name: 'socialaccount_callback' }),\n path('<str:provider>/token/', nativeTokenView, { name: 'socialaccount_native_token' }),\n])\n"],"mappings":";;;;;;;;;;;AACA,SAAS,oBAAoB;AAC7B,SAAS,eAAe;;;ACFxB,SAAS,qBAAqB;AAoDvB,SAAS,iBAAyC;AACvD,QAAM,WAAY,cAAc,GAAG,YAAY,CAAC;AAChD,QAAM,IAAK,SAAS,iBAAiB,CAAC;AACtC,SAAO;AAAA,IACL,WAAW,EAAE,aAAa,CAAC;AAAA,IAC3B,SAAS,EAAE;AAAA,IACX,YAAY,EAAE,eAAe;AAAA,IAC7B,qBAAqB,EAAE,wBAAwB;AAAA,IAC/C,eAAe,EAAE,kBAAkB;AAAA,IACnC,YAAY,EAAE,gBAAgB;AAAA,IAC9B,aAAa,EAAE,gBAAgB;AAAA,IAC/B,eAAe,EAAE,kBAAkB;AAAA,IACnC,aAAa,EAAE;AAAA,IACf,eAAe,EAAE,mBAAoB,SAAS,aAAoC;AAAA,EACpF;AACF;;;AD1DO,IAAM,oBAAN,cAAgC,MAAM;AAAA,EAC3C,YAAqB,UAAoB;AACvC,UAAM,mBAAmB;AADN;AAAA,EAErB;AAAA,EAFqB;AAGvB;AAOA,IAAM,mBAAmB;AAElB,IAAM,uBAAN,MAA2B;AAAA;AAAA,EAEhC,gBAAgB,IAAa,QAAiD;AAC5E,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,MAAM,eAAe,IAAa,QAAoC;AAAA,EAAC;AAAA;AAAA,EAGvE,oBAAoB,IAAa,OAAgD;AAC/E,UAAM,IAAI,eAAe;AACzB,QAAI,CAAC,EAAE,WAAY,QAAO;AAC1B,QAAI,EAAE,iBAAiB,CAAC,MAAM,QAAQ,MAAO,QAAO;AACpD,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,QAAQ,IAAa,QAA0B;AAC7C,UAAM,OAAO,aAAa;AAC1B,WAAO,IAAK,KAAa;AAAA,EAC3B;AAAA;AAAA,EAGA,aAAa,IAAa,OAAoB,MAAW,MAAuB;AAC9E,UAAM,IAAI,KAAK;AACf,UAAM,MAAM,CAAC,MAAc,CAAC,CAAC,EAAE,MAAM,WAAW,CAAC;AACjD,QAAI,KAAK,aAAa,OAAW,MAAK,EAAE,cAAc,IAAI,KAAK;AAC/D,QAAI,KAAK,UAAU,UAAa,IAAI,EAAE,WAAW,EAAG,MAAK,EAAE,WAAW,IAAI,KAAK;AAC/E,QAAI,IAAI,WAAW,KAAK,MAAM,QAAQ,UAAW,MAAK,YAAY,MAAM,QAAQ,UAAU,MAAM,GAAG,GAAG;AACtG,QAAI,IAAI,UAAU,KAAK,MAAM,QAAQ,SAAU,MAAK,WAAW,MAAM,QAAQ,SAAS,MAAM,GAAG,GAAG;AAClG,QAAI,IAAI,WAAW,KAAK,CAAC,MAAM,QAAQ,aAAa,MAAM,QAAQ,QAAQ,IAAI,UAAU,GAAG;AACzF,YAAM,CAAC,OAAO,GAAG,IAAI,IAAI,MAAM,QAAQ,KAAK,KAAK,EAAE,MAAM,KAAK;AAC9D,WAAK,aAAa,SAAS,IAAI,MAAM,GAAG,GAAG;AAC3C,WAAK,WAAW,KAAK,KAAK,GAAG,EAAE,MAAM,GAAG,GAAG;AAAA,IAC7C;AACA,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,MAAM,SAAS,IAAa,QAAqB,MAAyB;AACxE,QAAI,OAAO,KAAK,wBAAwB,WAAY,MAAK,oBAAoB;AAC7E,UAAM,KAAK,KAAK;AAChB,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,mBAAmB,OAA8B;AAC/C,UAAM,IAAI,MAAM;AAChB,WAAO,CAAC,EAAE,UAAU,EAAE,OAAO,MAAM,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,GAAG,MAAM,GAAG,GAAG,EAAE,EAAE,EAAE,EAAE;AAAA,MACtF,CAAC,MAAmB,OAAO,MAAM,YAAY,EAAE,KAAK,EAAE,SAAS;AAAA,IACjE;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,iBAAiB,IAAa,OAAqC;AACvE,UAAM,OAAO,aAAa;AAC1B,UAAM,QAAQ,KAAK;AACnB,UAAM,YAAa,KAAK,MAAM,SAAS,KAAK,GAA0C,aAAa;AACnG,UAAM,QAAQ,OAAO,SAAiB,KAAK,QAAQ,OAAO,EAAE,CAAC,GAAG,KAAK,UAAU,GAAG,KAAK,CAAQ,EAAE,OAAO;AACxG,eAAW,OAAO,KAAK,mBAAmB,KAAK,GAAG;AAChD,YAAM,OAAO,IAAI,KAAK,EAAE,QAAQ,QAAQ,EAAE,EAAE,QAAQ,kBAAkB,EAAE,EAAE,MAAM,GAAG,SAAS;AAC5F,UAAI,CAAC,KAAM;AACX,UAAI,CAAE,MAAM,MAAM,IAAI,EAAI,QAAO;AACjC,eAAS,IAAI,GAAG,IAAI,KAAK,KAAK;AAC5B,cAAM,SAAS,OAAO,CAAC;AACvB,cAAM,YAAY,GAAG,KAAK,MAAM,GAAG,YAAY,OAAO,MAAM,CAAC,GAAG,MAAM;AACtE,YAAI,CAAE,MAAM,MAAM,SAAS,EAAI,QAAO;AAAA,MACxC;AAAA,IACF;AACA,WAAO,OAAO,OAAO,WAAW,EAAE,QAAQ,MAAM,EAAE,EAAE,MAAM,GAAG,EAAE,CAAC;AAAA,EAClE;AAAA;AAAA,EAGA,sBAAsB,IAAa,UAAiC;AAClE,QAAI;AACF,aAAO,QAAQ,2BAA2B;AAAA,IAC5C,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA,EAGA,oBACE,IACA,QACsD;AACtD,WAAO;AAAA,EACT;AACF;AAEA,IAAM,QAAQ,oBAAI,QAAsC;AACxD,IAAI;AAEG,SAAS,aAAmC;AACjD,QAAM,MAAM,eAAe,EAAE;AAC7B,MAAI,CAAC,KAAK;AACR,iBAAa,IAAI,qBAAqB;AACtC,WAAO;AAAA,EACT;AACA,MAAI,IAAI,MAAM,IAAI,GAAG;AACrB,MAAI,CAAC,GAAG;AACN,QAAI,IAAI,IAAI;AACZ,UAAM,IAAI,KAAK,CAAC;AAAA,EAClB;AACA,SAAO;AACT;;;AEhIA,YAAY,UAAU;AACtB,SAAS,WAAW,MAAM,4BAA4B;;;ACDtD;AAAA;AAAA;AAAA;AAAA;;;ACCA,SAAS,WAAW,cAAc,WAAW;AAE7C,IAAO,kBAAQ,IAAI,UAAU;AAAA,EAC3B,SAAS;AAAA,EACT,cAAc,CAAC,CAAC,QAAQ,cAAc,CAAC;AAAA,EACvC,YAAY;AAAA,IACV,IAAI,YAAY;AAAA,MACd,MAAM;AAAA,MACN,QAAQ;AAAA,QACN,IAAI,EAAE,MAAM,gBAAgB,YAAY,KAAK;AAAA,QAC7C,MAAM;AAAA,UACJ,MAAM;AAAA,UACN,IAAI;AAAA,UACJ,UAAU;AAAA,UACV,SAAS;AAAA,UACT,aAAa;AAAA,UACb,aAAa;AAAA,QACf;AAAA,QACA,UAAU,EAAE,MAAM,aAAa,WAAW,KAAK,aAAa,WAAW;AAAA,QACvE,KAAK,EAAE,MAAM,aAAa,WAAW,KAAK,aAAa,MAAM;AAAA,QAC7D,WAAW,EAAE,MAAM,iBAAiB,SAAS,MAAM,aAAa,aAAa;AAAA,QAC7E,YAAY,EAAE,MAAM,iBAAiB,YAAY,MAAM,aAAa,cAAc;AAAA,QAClF,WAAW;AAAA,UACT,MAAM;AAAA,UACN,SAAS,EAAE,UAAU,YAAY;AAAA,UACjC,aAAa;AAAA,QACf;AAAA,MACF;AAAA,MACA,SAAS;AAAA,QACP,SAAS;AAAA,QACT,aAAa;AAAA,QACb,mBAAmB;AAAA,QACnB,gBAAgB,CAAC,CAAC,YAAY,KAAK,CAAC;AAAA,MACtC;AAAA,IACF,CAAC;AAAA,IACD,IAAI,YAAY;AAAA,MACd,MAAM;AAAA,MACN,QAAQ;AAAA,QACN,IAAI,EAAE,MAAM,gBAAgB,YAAY,KAAK;AAAA,QAC7C,UAAU,EAAE,MAAM,aAAa,WAAW,IAAI,aAAa,WAAW;AAAA,QACtE,YAAY,EAAE,MAAM,aAAa,WAAW,KAAK,OAAO,MAAM,aAAa,cAAc;AAAA,QACzF,MAAM,EAAE,MAAM,aAAa,WAAW,IAAI,aAAa,OAAO;AAAA,QAC9D,UAAU,EAAE,MAAM,aAAa,WAAW,KAAK,aAAa,YAAY;AAAA,QACxE,QAAQ,EAAE,MAAM,aAAa,WAAW,KAAK,OAAO,MAAM,aAAa,aAAa;AAAA,QACpF,KAAK,EAAE,MAAM,aAAa,WAAW,KAAK,OAAO,MAAM,aAAa,MAAM;AAAA,QAC1E,UAAU;AAAA,UACR,MAAM;AAAA,UACN,OAAO;AAAA,UACP,SAAS,EAAE,UAAU,YAAY;AAAA,UACjC,aAAa;AAAA,QACf;AAAA,MACF;AAAA,MACA,SAAS;AAAA,QACP,SAAS;AAAA,QACT,aAAa;AAAA,QACb,mBAAmB;AAAA,MACrB;AAAA,IACF,CAAC;AAAA,IACD,IAAI,YAAY;AAAA,MACd,MAAM;AAAA,MACN,QAAQ;AAAA,QACN,IAAI,EAAE,MAAM,gBAAgB,YAAY,KAAK;AAAA,QAC7C,KAAK;AAAA,UACH,MAAM;AAAA,UACN,IAAI;AAAA,UACJ,UAAU;AAAA,UACV,MAAM;AAAA,UACN,OAAO;AAAA,UACP,SAAS;AAAA,QACX;AAAA,QACA,SAAS;AAAA,UACP,MAAM;AAAA,UACN,IAAI;AAAA,UACJ,UAAU;AAAA,UACV,SAAS;AAAA,UACT,aAAa;AAAA,QACf;AAAA,QACA,OAAO,EAAE,MAAM,aAAa,aAAa,QAAQ;AAAA,QACjD,aAAa,EAAE,MAAM,aAAa,OAAO,MAAM,aAAa,eAAe;AAAA,QAC3E,WAAW,EAAE,MAAM,iBAAiB,MAAM,MAAM,OAAO,MAAM,aAAa,aAAa;AAAA,MACzF;AAAA,MACA,SAAS;AAAA,QACP,SAAS;AAAA,QACT,aAAa;AAAA,QACb,mBAAmB;AAAA,QACnB,gBAAgB,CAAC,CAAC,OAAO,SAAS,CAAC;AAAA,MACrC;AAAA,IACF,CAAC;AAAA,EACH;AACF,CAAC;;;ADpFM,IAAM,aAAa;AAAA,EACxB,gBAAgB;AAClB;;;ADHA,SAAS,UAA8B;AACrC,QAAM,OAAO;AACb,QAAM,MAAM,KAAK;AACjB,MAAI,CAAC,OAAO,CAAC,YAAY,KAAK,GAAG,KAAK,CAAC,aAAa,KAAK,KAAK,YAAY,EAAE,EAAG,QAAO;AACtF,SAAO;AACT;AAEA,SAAS,mBAA4C;AACnD,QAAM,QAAsC;AAC5C,SAAO,OAAO,UAAU,aAAa,MAAM,iBAAiB,kBAAU,IAAI;AAC5E;AAGO,IAAM,mBAAN,cAA+B,UAAU;AAAA,EAC9C,OAAO;AAAA,EACE,QAAQ;AAAA,EACR,cAAc;AAAA,EACd,OAAO,QAAQ;AAAA,EACf,aAAa,iBAAiB;AAAA,EAC9B,SAAS,EAAE,WAAW,eAAe,YAAY;AAAA,EAEjD,QAAc;AACrB,QAAI,CAAC,KAAK,YAAY,MAAM,GAAG;AAC7B,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;;;AGhCA,SAAS,SAAS,WAAW,gBAAAA,eAAc,gBAAgB,wBAAwB;AACnF,SAAS,SAAAC,QAAO,SAAS,SAAS,UAAU,YAAY,WAAAC,UAAS,iBAAAC,sBAAqB;AACtF;AAAA,EACE;AAAA,EAGA;AAAA,EACA,QAAAC;AAAA,EACA,UAAAC;AAAA,EACA;AAAA,OACK;AAEP,SAAS,cAAc,WAAW,iBAAiB;;;ACbnD,SAAS,cAAc;AAKvB,IAAM,IAAI;AACV,SAAS,UAAa,KAAa,MAAkB;AACnD,QAAM,IAAI,OAAO,IAAI,GAAG;AACxB,MAAI,CAAC,EAAE,CAAC,EAAG,GAAE,CAAC,IAAI,KAAK;AACvB,SAAO,EAAE,CAAC;AACZ;AAGO,IAAM,iBAA6D;AAAA,EACxE;AAAA,EACA,MAAM,IAAI,OAAO,gBAAgB;AACnC;AAEO,IAAM,qBACX,UAAU,uCAAuC,MAAM,IAAI,OAAO,oBAAoB,CAAC;AAElF,IAAM,uBACX,UAAU,yCAAyC,MAAM,IAAI,OAAO,sBAAsB,CAAC;AAEtF,IAAM,uBAAuE;AAAA,EAClF;AAAA,EACA,MAAM,IAAI,OAAO,sBAAsB;AACzC;;;AC1BA,SAAS,kBAAAC,iBAAkC,MAAM,cAAc;;;ACE/D,SAAS,wBAAAC,6BAA4B;AACrC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AAYA,IAAe,WAAf,MAAwB;AAAA;AAAA,EAIpB,eAAwB;AAAA;AAAA,EAExB,eAAyB,CAAC;AAAA,EAInC,MAAM,UAAsC;AAC1C,WAAO,SAAS,SAAS,KAAK;AAAA,EAChC;AAAA;AAAA,EAGA,cAAc,SAAkB,UAAqC;AACnE,QAAI,SAAS,mBAAmB,OAAW,QAAO,SAAS,kBAAkB,CAAC,CAAC,QAAQ;AACvF,WAAO,QAAQ,kBAAkB,QAAQ,CAAC,CAAC,QAAQ;AAAA,EACrD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,kBACJ,KACA,QACkB;AAClB,UAAM,WAAW,KAAK,eAAe,GAAG;AACxC,QAAI,EAAE,oBAAoB,iBAAiB,CAAC,OAAO,SAAS;AAC1D,YAAM,IAAI,WAAW,GAAG,KAAK,IAAI,iDAAiD,aAAa;AAAA,IACjG;AACA,UAAM,YAAY,CAAC,IAAI,IAAI,UAAU,GAAK,IAAI,IAAI,UAAU,aAAsC,CAAC,CAAE;AACrG,QAAI;AACJ,QAAI;AACJ,eAAW,OAAO,WAAW;AAC3B,UAAI;AACF,cAAM,IAAI,KAAK,eAAe,EAAE,GAAG,KAAK,KAAK,EAAE,GAAG,IAAI,KAAK,UAAU,IAAI,EAAE,CAAC;AAC5E,iBAAS,MAAM,EAAE,gBAAgB,OAAO,OAAO;AAC/C;AAAA,MACF,SAAS,KAAK;AACZ,oBAAY;AAAA,MACd;AAAA,IACF;AACA,QAAI,CAAC;AACH,YAAM,qBAAqB,QACvB,IAAI,WAAW,UAAU,SAAS,eAAe,IACjD,IAAI,WAAW,mBAAmB;AACxC,WAAO,KAAK,kBAAkB,IAAI,KAAK,MAAM;AAAA,EAC/C;AAAA,EAEA,kBAAkB,KAAa,QAAsC;AACnE,WAAO,kBAAkB,KAAK,MAAM;AAAA,EACtC;AACF;AAEA,SAAS,OAAO,KAAsBC,WAAoB;AACxD,SAAO;AAAA,IACL,MAAM,IAAI;AAAA,IACV,UAAU,IAAI,IAAI;AAAA,IAClB,cAAc,IAAI,IAAI;AAAA,IACtB,aAAa,IAAI;AAAA,IACjB,OAAOA,UAAS,MAAM,IAAI,QAAQ;AAAA,IAClC,qBAAqB,IAAI,SAAS;AAAA,EACpC;AACF;AAGA,SAAS,KACP,KACAA,WACA,QACA,QAAiC,CAAC,GACpB;AACd,SAAO,IAAI;AAAA,IACT;AAAA,MACE,GAAG,OAAO,KAAKA,SAAQ;AAAA,MACvB;AAAA,MACA,SAAS,OAAO,WACdA,UAAS,kBAAkB,IAAI,KAAM,OAAO,IAAwC,MAAM;AAAA,MAC5F,GAAG;AAAA,IACL;AAAA,IACA,IAAI;AAAA,EACN;AACF;AAIO,IAAM,iBAAN,cAA6B,SAAS;AAAA,EAClC,KAAK;AAAA,EACL,OAAO;AAAA,EACE,eAAe,CAAC,aAAa,YAAY;AAAA,EAEnD,IAAI,KAA8B;AACxC,WAAO,OAAO,IAAI,IAAI,UAAU,UAAU,wBAAwB,EAAE,QAAQ,QAAQ,EAAE;AAAA,EACxF;AAAA,EAEA,eAAe,KAAsC;AACnD,UAAM,MAAM,OAAO,IAAI,IAAI,UAAU,UAAU,oBAAoB,EAAE,QAAQ,QAAQ,EAAE;AACvF,UAAM,MAAM,KAAK,IAAI,GAAG;AACxB,WAAO,IAAI;AAAA,MACT;AAAA,QACE,GAAG,OAAO,KAAK,IAAI;AAAA,QACnB,kBAAkB,GAAG,GAAG;AAAA,QACxB,UAAU,GAAG,GAAG;AAAA,QAChB,SAAS,OAAO,SAAS,MAAM,KAAK,QAAQ,IAAI,KAAK,KAAK,CAAC,QAAQ,EAAE,cAAc,GAAG,CAAC;AAAA,MACzF;AAAA,MACA,IAAI;AAAA,IACN;AAAA,EACF;AAAA,EAEA,MAAc,QAAQ,KAAa,KAAa,KAAsD;AACpG,UAAM,OAAO,MAAM,IAAI,GAAG,GAAG,OAAO;AACpC,QAAI,QAA4B,KAAK,SAAS;AAC9C,QAAI,WAAW;AACf,QAAI;AACF,YAAM,SAAU,MAAM,IAAI,GAAG,GAAG,cAAc;AAK9C,YAAM,OAAO,MAAM,QAAQ,MAAM,IAAI,SAAS,CAAC;AAC/C,YAAM,UAAU,KAAK,KAAK,CAAC,MAAM,EAAE,WAAW,EAAE,QAAQ,KAAK,KAAK,KAAK,CAAC,MAAM,EAAE,QAAQ;AACxF,UAAI,SAAS;AACX,gBAAQ,QAAQ;AAChB,mBAAW;AAAA,MACb;AAAA,IACF,QAAQ;AAAA,IAER;AACA,WAAO;AAAA,MACL,UAAU;AAAA,MACV,IAAI,OAAO,KAAK,EAAE;AAAA,MAClB,UAAU,KAAK;AAAA,MACf,MAAM,KAAK,QAAQ;AAAA,MACnB;AAAA,MACA,eAAe;AAAA,MACf,WAAW,KAAK;AAAA,MAChB,KAAK;AAAA,IACP;AAAA,EACF;AAAA;AAAA,EAGA,MAAe,kBAAkB,KAAsB,QAAoD;AACzG,QAAI,CAAC,OAAO;AACV,YAAM,IAAI,WAAW,2DAA2D,aAAa;AAC/F,UAAM,MAAM,KAAK,IAAI,GAAG;AACxB,UAAM,MAAM,MAAM,cAAc,GAAG,GAAG,iBAAiB,mBAAmB,IAAI,IAAI,QAAQ,CAAC,UAAU;AAAA,MACnG,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,eAAe,SAAS,KAAK,GAAG,IAAI,IAAI,QAAQ,IAAI,IAAI,IAAI,UAAU,EAAE,EAAE,CAAC;AAAA,QAC3E,QAAQ;AAAA,QACR,gBAAgB;AAAA,MAClB;AAAA,MACA,MAAM,KAAK,UAAU,EAAE,cAAc,OAAO,YAAY,CAAC;AAAA,IAC3D,CAAC;AACD,QAAI,CAAC,IAAI,GAAI,OAAM,IAAI,WAAW,wDAAwD,eAAe;AACzG,UAAM,UAAU,EAAE,eAAe,UAAU,OAAO,WAAW,GAAG;AAChE,WAAO,KAAK,QAAQ,IAAI,KAAK,KAAK,CAAC,QAAQ,QAAQ,KAAK,EAAE,QAAQ,CAAC,CAAC;AAAA,EACtE;AACF;AAIO,IAAM,iBAAN,cAA6B,SAAS;AAAA,EAClC,KAAK;AAAA,EACL,OAAO;AAAA,EACE,eAAe,CAAC,UAAU,SAAS,SAAS;AAAA,EAE9D,eAAe,KAAsC;AACnD,WAAO,KAAK,KAAK,MAAM,6BAA6B;AAAA,EACtD;AACF;AAIO,IAAM,mBAAN,cAA+B,SAAS;AAAA,EACpC,KAAK;AAAA,EACL,OAAO;AAAA,EACE,eAAe,CAAC,SAAS,gBAAgB;AAAA,EAEnD,MAAM,KAA8B;AAC1C,WAAO,8BAA8B,OAAO,IAAI,SAAS,WAAW,IAAI,IAAI,UAAU,WAAW,OAAO,CAAC;AAAA,EAC3G;AAAA,EAEA,eAAe,KAAsC;AACnD,UAAM,UAAU,OAAO,IAAI,SAAS,WAAW,IAAI,IAAI,UAAU,WAAW,OAAO;AACnF,UAAM,QAAQ,KAAK,MAAM,GAAG;AAC5B,WAAO,IAAI;AAAA,MACT;AAAA,QACE,GAAG,OAAO,KAAK,IAAI;AAAA,QACnB,gBAAgB;AAAA,QAChB,kBAAkB,4BAA4B,OAAO;AAAA,QACrD,UAAU,GAAG,KAAK;AAAA,QAClB,SAAS,OAAO,IAAI,MAClB,KAAK;AAAA,UACH,IAAI;AAAA,UACJ,MAAM,EAAE,cAAc,GAAG,KAAK,uDAAuD;AAAA,QACvF;AAAA,MACJ;AAAA,MACA,IAAI;AAAA,IACN;AAAA,EACF;AAAA,EAEQ,QAAQ,KAAa,IAAkC;AAC7D,WAAO;AAAA,MACL,UAAU;AAAA,MACV,IAAI,OAAO,GAAG,EAAE;AAAA,MAChB,MAAM,GAAG;AAAA,MACT,WAAW,GAAG;AAAA,MACd,UAAU,GAAG;AAAA,MACb,OAAO,GAAG;AAAA;AAAA,MAEV,eAAe;AAAA,MACf,WAAW,GAAG,SAAS,MAAM;AAAA,MAC7B,KAAK;AAAA,IACP;AAAA,EACF;AAAA;AAAA,EAGA,MAAe,kBAAkB,KAAsB,QAAoD;AACzG,QAAI,CAAC,OAAO;AACV,YAAM,IAAI,WAAW,6DAA6D,aAAa;AACjG,UAAM,QAAQ,KAAK,MAAM,GAAG;AAC5B,UAAM,WAAW,GAAG,IAAI,IAAI,QAAQ,IAAI,IAAI,IAAI,UAAU,EAAE;AAC5D,UAAM,QAAQ,MAAM;AAAA,MAClB,GAAG,KAAK,4BAA4B,mBAAmB,OAAO,WAAW,CAAC,iBAAiB,mBAAmB,QAAQ,CAAC;AAAA,IACzH;AACA,QAAI,CAAC,MAAM,MAAM,YAAY,OAAO,MAAM,KAAK,MAAM,MAAM,IAAI,IAAI,UAAU;AAC3E,YAAM,IAAI,WAAW,kDAAkD,eAAe;AAAA,IACxF;AACA,UAAM,KAAK,MAAM,QAAQ,GAAG,KAAK,yDAAyD;AAAA,MACxF,SAAS,EAAE,eAAe,UAAU,OAAO,WAAW,GAAG;AAAA,IAC3D,CAAC;AACD,WAAO,KAAK,QAAQ,IAAI,KAAK,EAAE;AAAA,EACjC;AACF;AAIO,IAAM,oBAAN,cAAgC,SAAS;AAAA,EACrC,KAAK;AAAA,EACL,OAAO;AAAA,EACE,eAAe,CAAC,UAAU,SAAS,WAAW,WAAW;AAAA,EAE3E,eAAe,KAAsC;AACnD,UAAM,SAAS,OAAO,IAAI,IAAI,UAAU,UAAU,IAAI,SAAS,UAAU,QAAQ;AACjF,UAAM,QAAQ,CAAC,UAAU,iBAAiB,WAAW,EAAE,SAAS,MAAM;AACtE,WAAO,KAAK,KAAK,MAAM,qCAAqC,MAAM,SAAS;AAAA;AAAA,MAEzE,kBAAkB,QACd,CAAC,QAAgB,gEAAgE,KAAK,GAAG,IACzF;AAAA,MACJ,eAAe;AAAA,IACjB,CAAC;AAAA,EACH;AAAA,EAES,kBAAkB,KAAa,QAAsC;AAC5E,UAAM,IAAI,kBAAkB,KAAK,MAAM;AAEvC,WAAO,EAAE,GAAG,GAAG,IAAI,OAAO,OAAO,OAAO,OAAO,GAAG,GAAG,eAAe,MAAM;AAAA,EAC5E;AAAA,EAES,cAAc,SAAkB,UAAqC;AAC5E,WAAO,SAAS,mBAAmB,QAAQ,CAAC,CAAC,QAAQ;AAAA,EACvD;AACF;AAIO,IAAM,kBAAN,cAA8B,SAAS;AAAA,EACnC,KAAK;AAAA,EACL,OAAO;AAAA,EACE,eAAe,CAAC,YAAY,OAAO;AAAA,EAErD,eAAe,KAAsC;AACnD,WAAO,IAAI;AAAA,MACT;AAAA,QACE,GAAG,OAAO,KAAK,IAAI;AAAA,QACnB,kBAAkB;AAAA,QAClB,UAAU;AAAA,QACV,SAAS,OAAO,IAAI,MAAM;AACxB,gBAAM,KAAK,MAAM,EAAE,cAAc,mCAAmC;AACpE,iBAAO;AAAA,YACL,UAAU,IAAI;AAAA,YACd,IAAI,OAAO,GAAG,EAAE;AAAA,YAChB,UAAU,GAAG;AAAA,YACb,MAAM,GAAG,eAAe,GAAG;AAAA,YAC3B,OAAO,GAAG,SAAS;AAAA,YACnB,eAAe,GAAG,aAAa;AAAA,YAC/B,WAAW,GAAG,SAAS,sCAAsC,GAAG,EAAE,IAAI,GAAG,MAAM,SAAS;AAAA,YACxF,KAAK;AAAA,UACP;AAAA,QACF;AAAA,MACF;AAAA,MACA,IAAI;AAAA,IACN;AAAA,EACF;AAAA,EAEA,MAAe,oBAAsC;AACnD,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACF;AAIO,IAAM,iBAAN,cAA6B,SAAS;AAAA,EAClC,KAAK;AAAA,EACL,OAAO;AAAA,EACE,eAAe,CAAC,UAAU,SAAS,SAAS;AAAA,EAE9D,eAAe,KAAsC;AACnD,UAAM,MAAM,OAAO,IAAI,IAAI,UAAU,OAAO,IAAI,SAAS,cAAc,oBAAoB,EAAE;AAAA,MAC3F;AAAA,MACA;AAAA,IACF;AACA,WAAO,KAAK,KAAK,MAAM,GAAG;AAAA,EAC5B;AAAA,EAES,kBAAkB,KAAa,QAAsC;AAC5E,WAAO,EAAE,GAAG,kBAAkB,KAAK,MAAM,GAAG,UAAU,OAAO,YAAY,OAAO,mBAAmB;AAAA,EACrG;AACF;AAIO,IAAM,wBAAN,cAAoC,SAAS;AAAA,EACzC,KAAK;AAAA,EACL,OAAO;AAAA,EACE,eAAe;AAAA,EACf,eAAe,CAAC,UAAU,SAAS,SAAS;AAAA,EAE9D,eAAe,KAAsC;AACnD,UAAM,SAAS,IAAI,IAAI,UAAU,aAAa,IAAI,IAAI,UAAU;AAChE,QAAI,OAAO,WAAW,UAAU;AAC9B,YAAM,IAAID;AAAA,QACR,2BAA2B,IAAI,GAAG;AAAA,MACpC;AAAA,IACF;AACA,WAAO,KAAK,KAAK,MAAM,MAAM;AAAA,EAC/B;AACF;AAIA,IAAM,MAAM,uBAAO,IAAI,4BAA4B;AACnD,IAAM,YAAmC,MAAM;AAC7C,QAAME,KAAI;AACV,MAAI,CAACA,GAAE,GAAG,GAAG;AACX,UAAM,IAAI,oBAAI,IAAsB;AACpC,eAAW,KAAK;AAAA,MACd,IAAI,eAAe;AAAA,MACnB,IAAI,eAAe;AAAA,MACnB,IAAI,iBAAiB;AAAA,MACrB,IAAI,kBAAkB;AAAA,MACtB,IAAI,gBAAgB;AAAA,MACpB,IAAI,eAAe;AAAA,MACnB,IAAI,sBAAsB;AAAA,IAC5B,GAAG;AACD,QAAE,IAAI,EAAE,IAAI,CAAC;AAAA,IACf;AACA,IAAAA,GAAE,GAAG,IAAI;AAAA,EACX;AACA,SAAOA,GAAE,GAAG;AACd,GAAG;AAGI,SAAS,iBAAiBD,WAA0B;AACzD,WAAS,IAAIA,UAAS,IAAIA,SAAQ;AACpC;AAEO,SAAS,YAAY,IAAkC;AAC5D,SAAO,SAAS,IAAI,EAAE;AACxB;AAEO,SAAS,eAA2B;AACzC,SAAO,CAAC,GAAG,SAAS,OAAO,CAAC;AAC9B;;;ACtYA,SAAS,QAAQ,KAA6B;AAC5C,SAAO;AAAA,IACL,UAAU,IAAI;AAAA,IACd,QAAQ,IAAI,UAAU;AAAA,IACtB,KAAK,IAAI,OAAO;AAAA,IAChB,YAAY,IAAI,cAAc;AAAA,IAC9B,MAAM,IAAI;AAAA,IACV,UAAW,IAAI,YAAwC,CAAC;AAAA,EAC1D;AACF;AAEA,eAAe,SAAS,QAAuD;AAC7E,MAAI;AACF,WAAO,MAAM,UAAU,QAAQ,OAAO,MAAM,EAAE,QAAQ,IAAI;AAAA,EAC5D,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAGA,eAAsB,gBAAgB,KAA+C;AACnF,QAAM,MAAM,eAAe,EAAE;AAC7B,QAAM,SAAS,YAAY,GAAG;AAC9B,MAAI,UAAU,CAAC,OAAO,cAAc;AAClC,UAAM,WAAW,IAAI,GAAG,KAAK,CAAC;AAC9B,QAAI,SAAS,IAAK,QAAO,EAAE,KAAK,UAAU,QAAQ,KAAK,SAAS,KAAK,SAAS;AAC9E,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,EAAE,UAAU,IAAI,CAAC;AAC9C,WAAO,MAAM,EAAE,KAAK,UAAU,QAAQ,KAAK,QAAQ,GAAG,GAAG,UAAU,IAAI,IAAI;AAAA,EAC7E;AACA,aAAWE,aAAY,aAAa,EAAE,OAAO,CAAC,MAAM,EAAE,YAAY,GAAG;AACnE,UAAM,WAAW,IAAIA,UAAS,EAAE,KAAK,CAAC;AACtC,UAAM,MAAM,SAAS,MAAM,KAAK,CAAC,MAAM,EAAE,eAAe,GAAG;AAC3D,QAAI,IAAK,QAAO,EAAE,KAAK,UAAAA,WAAU,KAAK,SAAS;AAC/C,UAAM,CAAC,GAAG,IAAI,MAAM,SAAS,EAAE,UAAUA,UAAS,IAAI,YAAY,IAAI,CAAC;AACvE,QAAI,IAAK,QAAO,EAAE,KAAK,UAAAA,WAAU,KAAK,QAAQ,GAAG,GAAG,UAAU,IAAI;AAAA,EACpE;AACA,SAAO;AACT;AAGA,eAAsB,sBAAmD;AACvE,QAAM,MAAM,eAAe,EAAE;AAC7B,QAAM,MAA0B,CAAC;AACjC,QAAM,OAAO,oBAAI,IAAY;AAC7B,aAAWA,aAAY,aAAa,GAAG;AACrC,UAAM,WAAW,IAAIA,UAAS,EAAE,KAAK,CAAC;AACtC,QAAIA,UAAS,cAAc;AACzB,iBAAW,OAAO,SAAS,QAAQ,CAAC,GAAG;AACrC,YAAI,IAAI,cAAc,CAAC,KAAK,IAAI,IAAI,UAAU,GAAG;AAC/C,eAAK,IAAI,IAAI,UAAU;AACvB,cAAI,KAAK,EAAE,KAAK,IAAI,YAAY,UAAAA,WAAU,KAAK,SAAS,CAAC;AAAA,QAC3D;AAAA,MACF;AACA,iBAAW,OAAO,MAAM,SAAS,EAAE,UAAUA,UAAS,GAAG,CAAC,GAAG;AAC3D,YAAI,IAAI,cAAc,CAAC,KAAK,IAAI,IAAI,UAAU,GAAG;AAC/C,eAAK,IAAI,IAAI,UAAU;AACvB,cAAI,KAAK,EAAE,KAAK,IAAI,YAAY,UAAAA,WAAU,KAAK,QAAQ,GAAG,GAAG,UAAU,IAAI,CAAC;AAAA,QAC9E;AAAA,MACF;AAAA,IACF,WAAW,SAAS,KAAK;AACvB,WAAK,IAAIA,UAAS,EAAE;AACpB,UAAI,KAAK,EAAE,KAAKA,UAAS,IAAI,UAAAA,WAAU,KAAK,SAAS,KAAK,SAAS,CAAC;AAAA,IACtE;AAAA,EACF;AACA,aAAW,OAAO,MAAM,SAAS,CAAC,CAAC,GAAG;AACpC,UAAMA,YAAW,YAAY,IAAI,QAAQ;AACzC,QAAIA,aAAY,CAACA,UAAS,gBAAgB,CAAC,KAAK,IAAI,IAAI,QAAQ,GAAG;AACjE,WAAK,IAAI,IAAI,QAAQ;AACrB,UAAI,KAAK,EAAE,KAAK,IAAI,UAAU,UAAAA,WAAU,KAAK,QAAQ,GAAG,GAAG,UAAU,IAAI,IAAI,QAAQ,KAAK,CAAC,GAAG,IAAI,CAAC;AAAA,IACrG;AAAA,EACF;AACA,SAAO;AACT;;;AFjFA,IAAM,UAAU;AAEhB,eAAsB,YAAY,OAAoB,SAAuC;AAC3F,MAAI,CAAC,eAAe,EAAE,eAAe,CAAC,MAAM,QAAQ,YAAa;AACjE,QAAM,IAAI,MAAM;AAChB,QAAM,MAAM,MAAM,OAAO;AACzB,QAAM,WAAW,MAAM,YAAY,QAAQ,OAAO,EAAE,SAAS,IAAI,CAAQ,EAAE,MAAM;AACjF,QAAM,SAAS;AAAA,IACb,OAAO,MAAM,KAAK,EAAE,aAAa,OAAO;AAAA,IACxC,aAAa,EAAE,eAAe,MAAM,KAAK,EAAE,cAAc,OAAO,IAAK,UAAU,eAAe;AAAA,IAC9F,WAAW,EAAE,YAAY,IAAI,KAAK,EAAE,SAAS,IAAI;AAAA,EACnD;AACA,MAAI,UAAU;AACZ,WAAO,OAAO,UAAU,MAAM;AAC9B,UAAM,SAAS,KAAK;AAAA,EACtB,OAAO;AACL,UAAM,YAAY,QAAQ,OAAO,EAAE,SAAS,KAAK,GAAG,OAAO,CAAQ;AAAA,EACrE;AACF;AAMA,eAAsB,eAAe,SAAgD;AACnF,QAAM,MAAM,MAAM,YAAY,QAAQ,OAAO,EAAE,QAAQ,CAAQ,EAAE,MAAM;AACvE,MAAI,CAAC,IAAK,QAAO;AACjB,QAAM,SAAS,MAAM,OAAO,IAAI,OAAO,OAAO;AAC9C,QAAM,YAAY,IAAI,YAAY,IAAI,KAAK,IAAI,SAAgB,EAAE,QAAQ,IAAI;AAC7E,MAAI,WAAW,CAAC,aAAa,YAAY,MAAS,KAAK,IAAI,GAAI,QAAO;AACtE,QAAM,UAAU,IAAI,cAAc,MAAM,OAAO,IAAI,aAAa,OAAO,IAAI;AAC3E,MAAI,CAAC,QAAS,QAAO;AACrB,QAAM,WAAW,MAAM,gBAAgB,QAAQ,QAAQ;AACvD,MAAI,CAAC,SAAU,QAAO;AACtB,QAAM,WAAW,SAAS,SAAS,eAAe;AAAA,IAChD,KAAK,SAAS;AAAA,IACd,KAAK,SAAS;AAAA,IACd,UAAU,SAAS;AAAA,IACnB,aAAa;AAAA,IACb,QAAQ,YAAY;AAAA,EACtB,CAAC;AACD,MAAI,EAAE,oBAAoBC,iBAAiB,QAAO;AAClD,MAAI;AACJ,MAAI;AACF,aAAS,OAAO,MAAM,SAAS,OAAO,GAAG,QAAQ,OAAO;AAAA,EAC1D,QAAQ;AACN,WAAO;AAAA,EACT;AACA,MAAI,QAAQ,MAAM,KAAK,OAAO,aAAa,OAAO;AAClD,MAAI,OAAO,aAAc,KAAI,cAAc,MAAM,KAAK,OAAO,cAAc,OAAO;AAClF,MAAI,YAAa,OAAO,YAAY,IAAI,KAAK,OAAO,SAAS,IAAI;AACjE,QAAM,IAAI,KAAK;AACf,SAAO,OAAO;AAChB;;;AF1BO,IAAM,kBAAN,cAA8B,MAAM;AAAA,EACzC,YACE,SACS,SAAS,KACT,OAAO,uBAChB;AACA,UAAM,OAAO;AAHJ;AACA;AAAA,EAGX;AAAA,EAJW;AAAA,EACA;AAIb;AAEO,SAAS,WACd,UACA,SACA,MACa;AACb,SAAO;AAAA,IACL,GAAG;AAAA,IACH,SAAS,EAAE,GAAG,SAAS,UAAU,SAAS,IAAI;AAAA,IAC9C,QAAQ,KAAK;AAAA,IACb,eAAe,SAAS,SAAS,cAAc,SAAS,SAAS,QAAQ;AAAA,IACzE,SAAS,KAAK,WAAW;AAAA,IACzB,MAAM,KAAK;AAAA,EACb;AACF;AAIA,SAAS,mBAA2B;AAClC,SAAO;AAAA,IACJC,eAAc,GAAG,SAAS,sBAA6C;AAAA,EAC1E;AACF;AAEA,IAAM,eAAe;AACrB,IAAM,WAAW;AAGjB,eAAsB,cAAc,MAA4B;AAC9D,SAAOC;AAAA,IACL,KAAK,UAAU;AAAA,MACb,KAAK,OAAO,KAAK,EAAE;AAAA,MACnB,KAAK,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI,IAAI;AAAA,MACrC,KAAK,YAAY,EAAE;AAAA,IACrB,CAAC;AAAA,IACD;AAAA,EACF;AACF;AAGA,eAAsB,gBAAgB,MAAmC;AACvE,QAAM,MAAM,MAAMC,QAAO,MAAM,YAAY;AAC3C,MAAI,CAAC,IAAK,QAAO;AACjB,MAAI;AACJ,MAAI;AACF,WAAO,KAAK,MAAM,GAAG;AAAA,EACvB,QAAQ;AACN,WAAO;AAAA,EACT;AACA,MAAI,CAAC,KAAK,OAAO,KAAK,MAAM,KAAK,IAAI,IAAI,IAAM,QAAO;AACtD,QAAM,MAAM,yBAAyB,KAAK,GAAG;AAC7C,MAAI;AACF,QAAI,MAAMC,OAAM,IAAI,GAAG,EAAG,QAAO;AACjC,UAAMA,OAAM,IAAI,KAAK,GAAG,WAAW,CAAC;AAAA,EACtC,QAAQ;AAAA,EAER;AACA,QAAM,OAAOC,cAAa;AAC1B,QAAM,OAAO,MAAM,KAAK,QAAQ,OAAO,EAAE,IAAI,KAAK,MAAM,GAAG,SAAS,KAAK,GAAG,EAAE,CAAQ,EAAE,MAAM;AAC9F,SAAO,QAAS,KAAa,aAAa,QAAQ,OAAO;AAC3D;AAGA,eAAsB,YAAY,GAAY,MAAW,OAAoB,MAA+B;AAC1G,QAAM,IAAI,eAAe;AACzB,MAAI,KAAK,aAAa,MAAO,OAAM,IAAI,gBAAgB,6BAA6B,KAAK,UAAU;AACnG,MAAI,EAAE,kBAAkB,OAAO;AAC7B,QAAI,SAAS,MAAO,QAAO,EAAE,KAAK,EAAE,GAAI,MAAM,iBAAiB,IAAI,GAAI,MAAM,SAAS,IAAI,EAAE,CAAC;AAC7F,QAAI,CAAC,EAAE;AACL,YAAM,IAAI,gBAAgB,qEAAqE,GAAG;AACpG,WAAO,EAAE,SAAS,GAAG,EAAE,WAAW,SAAS,mBAAmB,MAAM,cAAc,IAAI,CAAC,CAAC,IAAI,GAAG;AAAA,EACjG;AACA,QAAM,UAAU,GAAG,MAAM,iBAAiB,CAAC;AAC3C,MAAI,SAAS,MAAO,QAAO,EAAE,KAAK,EAAE,MAAM,SAAS,IAAI,EAAE,CAAC;AAC1D,QAAM,OAAO,MAAM;AACnB,SAAO,EAAE,SAAS,eAAe,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,OAAO,iBAAiB,GAAG,GAAG;AACvF;AAGA,eAAsB,cACpB,GACA,KACAC,WACA,MACmB;AACnB,QAAM,SAAS,MAAM,WAAW,EAAE,oBAAoB,GAAG,EAAE,UAAAA,WAAU,SAAS,IAAI,SAAS,MAAM,IAAI,KAAK,CAAC;AAC3G,MAAI,OAAQ,QAAO;AACnB,MAAI,SAAS,MAAO,QAAO,EAAE,KAAK,EAAE,QAAQ,IAAI,SAAS,MAAM,IAAI,KAAK,GAAG,IAAI,MAAa;AAC5F,QAAM,IAAI,eAAe;AACzB,MAAI,EAAE,kBAAkB,SAAS,EAAE,aAAa;AAC9C,WAAO,EAAE,SAAS,GAAG,EAAE,WAAW,UAAU,mBAAmB,IAAI,OAAO,CAAC,IAAI,GAAG;AAAA,EACpF;AACA,QAAM,MAAM,IAAI,IAAI,EAAE,eAAe,UAAU;AAC/C,MAAI,aAAa,IAAI,SAAS,IAAI,OAAO;AACzC,SAAO,EAAE,SAAS,GAAG,IAAI,QAAQ,GAAG,IAAI,MAAM,IAAI,GAAG;AACvD;AAIA,IAAM,gBAAgB;AACtB,IAAM,iBAAiB;AACvB,IAAM,aAAa;AAWnB,eAAsB,kBAAkB,GAAY,OAAmC;AACrF,QAAM,UAAyB;AAAA,IAC7B,KAAK,MAAM;AAAA,IACX,SAAS,MAAM;AAAA,IACf,QAAQ,eAAe,EAAE,cAAc,MAAM,SAAS;AAAA,IACtD,eAAe,MAAM;AAAA,IACrB,MAAM,MAAM;AAAA,IACZ,WAAW,KAAK,IAAI;AAAA,EACtB;AACA,YAAU,GAAG,eAAe,MAAMJ,MAAK,KAAK,UAAU,OAAO,GAAG,cAAc,GAAG;AAAA,IAC/E,MAAM;AAAA,IACN,UAAU;AAAA,IACV,QAAQ,SAAS,CAAC;AAAA,IAClB,UAAU;AAAA,IACV,QAAQ;AAAA,EACV,CAAC;AACH;AAEA,eAAsB,kBAAkB,GAA2C;AACjF,QAAM,MAAM,UAAU,GAAG,aAAa;AACtC,MAAI,CAAC,IAAK,QAAO;AACjB,QAAM,OAAO,MAAMC,QAAO,KAAK,cAAc;AAC7C,MAAI,CAAC,KAAM,QAAO;AAClB,MAAI;AACF,UAAM,IAAI,KAAK,MAAM,IAAI;AACzB,WAAO,KAAK,IAAI,IAAI,EAAE,aAAa,aAAa,MAAO,IAAI;AAAA,EAC7D,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAOO,SAAS,oBAAoB,GAAY,KAAyB;AACvE,MAAI,QAAQ;AAAA,IACV;AAAA,IACA,GAAG,aAAa,+CAA+C,SAAS,CAAC,IAAI,aAAa,EAAE;AAAA,EAC9F;AACA,SAAO;AACT;AAIA,eAAe,WAAW,OAAe,UAAsC;AAC7E,QAAM,OAAOI,cAAa;AAC1B,MAAI,KAAK,KAAK,QAAQ,OAAO,EAAE,CAAC,GAAG,KAAK,WAAW,UAAU,GAAG,MAAM,CAAQ;AAC9E,MAAI,aAAa,OAAW,MAAK,GAAG,QAAQ,EAAE,IAAI,SAAS,CAAQ;AACnE,SAAO,GAAG,OAAO;AACnB;AAEA,eAAe,KAAK,GAAY,OAAoB,MAAmC;AACrF,QAAM,UAAU,MAAM,cAAc,QAAQ,OAAO;AAAA,IACjD;AAAA,IACA,UAAU,MAAM;AAAA,IAChB,KAAK,MAAM,QAAQ;AAAA,IACnB,WAAW,MAAM,QAAQ;AAAA,EAC3B,CAAQ;AACR,QAAM,YAAY,OAAO,OAAO;AAChC,QAAM,mBAAmB,KAAK,eAAe,EAAE,GAAG,OAAO,QAAQ,CAAC;AAClE,SAAO;AACT;AAMA,eAAsB,OACpB,GACA,OACA,MACA,MAC8C;AAC9C,QAAM,UAAU,WAAW;AAC3B,QAAM,OAAOA,cAAa;AAC1B,QAAM,SAAmC,CAAC;AAC1C,QAAM,YAAY,KAAK,YAAY,IAAI,KAAK;AAC5C,QAAM,SAAS,KAAK,SAAS,IAAI,KAAK;AACtC,MAAI,KAAK,mBAAmB,KAAK,aAAa;AAC5C,QAAI,CAAC,SAAU,QAAO,KAAK,cAAc,IAAI,CAAC,yBAAyB;AAAA,aAC9D,MAAM,KAAK,QAAQ,OAAO,EAAE,CAAC,GAAG,KAAK,cAAc,UAAU,GAAG,SAAS,CAAQ,EAAE,OAAO,GAAG;AACpG,aAAO,KAAK,cAAc,IAAI,CAAC,2CAA2C;AAAA,IAC5E;AAAA,EACF;AACA,MAAI,CAAC,UAAU,eAAe,EAAE,iBAAiB,KAAK,mBAAmB,KAAK,cAAc;AAC1F,WAAO,KAAK,WAAW,IAAI,CAAC,yBAAyB;AAAA,EACvD,WAAW,SAAU,MAAM,WAAW,KAAK,GAAI;AAC7C,WAAO,KAAK,WAAW,IAAI;AAAA,MACzB,0EAA0E,MAAM,SAAS,IAAI;AAAA,IAC/F;AAAA,EACF;AACA,MAAI,OAAO,KAAK,MAAM,EAAE,OAAQ,QAAO;AACvC,MAAI,OAAO,QAAQ,QAAQ,GAAG,KAAK;AACnC,SAAO,QAAQ,aAAa,GAAG,OAAO,MAAM;AAAA,IAC1C,UAAU,KAAK,mBAAmB,KAAK,cAAc,QAAQ;AAAA,IAC7D,OAAO,SAAS;AAAA,EAClB,CAAC;AACD,SAAO,MAAM,QAAQ,SAAS,GAAG,OAAO,IAAI;AAC5C,QAAM,KAAK,GAAG,OAAO,IAAI;AACzB,SAAO,YAAY,GAAG,MAAM,OAAO,IAAI;AACzC;AAGA,eAAsB,oBAAoB,GAAY,OAAoB,MAA+B;AACvG,QAAM,UAAU,WAAW;AAC3B,QAAM,eAAe,KAAK,eAAe,EAAE,GAAG,MAAM,CAAC;AACrD,QAAM,QAAQ,eAAe,GAAG,KAAK;AACrC,QAAM,UAAU,QAAQ,CAAC;AACzB,QAAM,OAAOA,cAAa;AAG1B,QAAM,WAAW,MAAM,cAAc,QAAQ,OAAO,EAAE,UAAU,MAAM,KAAK,KAAK,MAAM,QAAQ,GAAG,CAAC,EAAE,MAAM;AAC1G,MAAI,UAAU;AACZ,aAAS,YAAY,MAAM,QAAQ;AACnC,UAAM,SAAS,KAAK;AACpB,UAAM,YAAY,OAAO,QAAQ;AACjC,UAAM,qBAAqB,KAAK,eAAe,EAAE,GAAG,OAAO,SAAS,SAAS,CAAC;AAC9E,UAAM,SAAU,SAAiB,UAAW,SAAiB;AAC7D,QAAI,MAAM,YAAY,WAAW;AAC/B,UAAI,CAAC,QAAQ;AACX,cAAM,IAAI,gBAAgB,wCAAwC,KAAK,gBAAgB;AACzF,UAAI,OAAO,MAAM,MAAM,OAAO,QAAQ,EAAE,GAAG;AACzC,cAAM,IAAI;AAAA,UACR,QAAQ,MAAM,SAAS,IAAI;AAAA,UAC3B;AAAA,UACA;AAAA,QACF;AAAA,MACF;AACA,aAAO,SAAS,QACZ,EAAE,KAAK,EAAE,WAAW,KAAK,CAAC,IAC1B,EAAE,SAAS,QAAQ,sBAAsB,GAAG,QAAQ,GAAG,GAAG;AAAA,IAChE;AACA,UAAM,OAAO,MAAM,KAAK,QAAQ,OAAO,EAAE,IAAI,OAAO,CAAQ,EAAE,MAAM;AACpE,QAAI,CAAC,KAAM,OAAM,IAAI,gBAAgB,qCAAqC,KAAK,cAAc;AAC7F,WAAO,YAAY,GAAG,MAAM,OAAO,IAAI;AAAA,EACzC;AAGA,MAAI,MAAM,YAAY,WAAW;AAC/B,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI,gBAAgB,wCAAwC,KAAK,gBAAgB;AACzF,UAAM,OAAO,MAAM,KAAK,QAAQ,OAAO,EAAE,IAAI,QAAQ,GAAG,CAAQ,EAAE,MAAM;AACxE,UAAM,UAAU,MAAM,KAAK,GAAG,OAAO,IAAI;AACzC,WAAO,SAAS,QACZ,EAAE,KAAK,EAAE,WAAW,KAAK,CAAC,IAC1B,EAAE,SAAS,QAAQ,sBAAsB,GAAG,OAAO,GAAG,GAAG;AAAA,EAC/D;AAGA,QAAM,IAAI,eAAe;AACzB,MAAI,EAAE,uBAAuB,MAAM,iBAAiB,MAAM,QAAQ,OAAO;AACvE,UAAM,UAAU,MAAM,KAAK,QACxB,OAAO,EAAE,CAAC,GAAG,KAAK,WAAW,UAAU,GAAG,MAAM,QAAQ,MAAM,CAAQ,EACtE,MAAM,CAAC;AACV,QAAI,QAAQ,WAAW,GAAG;AACxB,YAAM,KAAK,GAAG,OAAO,QAAQ,CAAC,CAAC;AAC/B,aAAO,YAAY,GAAG,QAAQ,CAAC,GAAG,OAAO,IAAI;AAAA,IAC/C;AAAA,EACF;AAGA,MAAI,CAAE,MAAM,QAAQ,gBAAgB,GAAG,KAAK,GAAI;AAC9C,UAAM,IAAI,gBAAgB,wBAAwB,KAAK,eAAe;AAAA,EACxE;AACA,MAAI,MAAM,QAAQ,oBAAoB,GAAG,KAAK,GAAG;AAC/C,UAAM,QACJ,MAAM,QAAQ,SAAS,CAAE,MAAM,WAAW,MAAM,QAAQ,KAAK,IAAK,MAAM,QAAQ,QAAQ;AAC1F,QAAI,SAAU,CAAC,EAAE,iBAAiB,CAAC,MAAM,QAAQ,SAAS,KAAK,mBAAmB,KAAK,aAAc;AACnG,YAAM,SAAS,MAAM;AAAA,QACnB;AAAA,QACA;AAAA,QACA;AAAA,UACE,UACE,KAAK,mBAAmB,KAAK,cAAc,QAAQ,MAAM,QAAQ,iBAAiB,GAAG,KAAK;AAAA,UAC5F;AAAA,QACF;AAAA,QACA;AAAA,MACF;AACA,UAAI,kBAAkB,SAAU,QAAO;AAAA,IACzC;AAAA,EACF;AACA,QAAM,kBAAkB,GAAG,KAAK;AAChC,MAAI,YAAY;AAChB,MAAI;AACF,gBAAYC,SAAQ,sBAAsB;AAAA,EAC5C,QAAQ;AAAA,EAER;AACA,MAAI,SAAS,OAAO;AAClB,WAAO,EAAE,KAAK,EAAE,QAAQ,sBAAsB,MAAM,mBAAmB,UAAU,GAAG,GAAG;AAAA,EACzF;AACA,SAAO,EAAE,SAAS,WAAW,GAAG;AAClC;;;AK5VA,SAAS,gBAAAC,eAAc,UAAU,oBAAAC,yBAAwB;AACzD;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAAC;AAAA,EACA;AAAA,EACA,WAAAC;AAAA,EACA;AAAA,EAEA;AAAA,OACK;AACP,SAAyC,YAAAC,iBAAgB;AAoBzD,SAAS,KAAK,OAAe,MAAc,SAAS,KAAe;AACjE,QAAM,OAAO,wIAAwI,WAAW,KAAK,CAAC,mSAAmS,WAAW,KAAK,CAAC,QAAQ,IAAI;AACte,SAAO,IAAI,SAAS,MAAM,EAAE,QAAQ,SAAS,EAAE,gBAAgB,2BAA2B,EAAE,CAAC;AAC/F;AAEA,SAAS,UAAU,GAAoB;AACrC,MAAI;AACF,WAAO,0DAA0D,WAAW,aAAa,CAAC,CAAC,CAAC;AAAA,EAC9F,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,IAAI,GAAgC;AAC3C,SAAO,OAAO,MAAM,YAAY,IAAI,IAAI;AAC1C;AAEA,eAAe,SAAS,GAAuC;AAC7D,QAAM,MAAM,EAAE,IAAI,MAAM,UAAU,KAAK;AACvC,QAAM,WAAW,MAAM,gBAAgB,GAAG;AAC1C,MAAI,CAAC;AACH,UAAM,IAAI,gBAAgB,qCAAqC,GAAG,MAAM,KAAK,kBAAkB;AACjG,SAAO;AACT;AAEA,SAAS,YAAY,GAAY,UAA4B;AAC3D,QAAM,cAAc,EAAE,IAAI,KAAK,QAAQ,yBAAyB,iBAAiB;AACjF,QAAM,WAAY,WAAmB,uBAAO,IAAI,+BAA+B,CAAC;AAGhF,QAAM,OAAO,WAAW,SAAS,KAAK,WAAW;AACjD,MAAI,KAAM,QAAO;AACjB,SAAO,SAAS,SAAS,eAAe;AAAA,IACtC,KAAK,SAAS;AAAA,IACd,KAAK,SAAS;AAAA,IACd,UAAU,SAAS;AAAA,IACnB;AAAA;AAAA,IAEA,QAAQ,aAAa,EAAE,aAAa,KAAK;AAAA,EAC3C,CAAC;AACH;AAGA,SAAS,QAAQ,MAAqC,IAAqD;AACzG,SAAO,OAAO,MAAM;AAClB,UAAM,IAAI,OAAO,SAAS,aAAa,KAAK,CAAC,IAAI;AACjD,QAAI;AACF,aAAO,MAAM,GAAG,CAAC;AAAA,IACnB,SAAS,KAAK;AACZ,UAAI,eAAe,kBAAmB,QAAO,IAAI;AACjD,UAAI,eAAe,gBAAiB,QAAO,cAAc,GAAG,KAAK,EAAE,IAAI,MAAM,UAAU,KAAK,IAAI,CAAC;AACjG,YAAM;AAAA,IACR;AAAA,EACF;AACF;AAGA,SAAS,YAAY,GAAkB;AACrC,MAAI,EAAE,EAAE,IAAI,OAAO,cAAc,KAAK,IAAI,SAAS,kBAAkB,GAAG;AACtE,UAAM,IAAI,gBAAgB,sDAAsD,KAAK,eAAe;AAAA,EACtG;AACF;AAKO,IAAM,gBAA8B,OAAO,MAAM;AACtD,QAAM,OAAO,MAAM,oBAAoB;AACvC,SAAO,EAAE,KAAK;AAAA,IACZ,WAAW,KAAK,IAAI,CAAC,OAAO;AAAA,MAC1B,IAAI,EAAE;AAAA,MACN,MAAM,EAAE,IAAI,QAAQ,EAAE,SAAS;AAAA,MAC/B,UAAU,EAAE,SAAS;AAAA,MACrB,UAAUC,SAAQ,uBAAuB,EAAE,UAAU,EAAE,IAAI,CAAC;AAAA,MAC5D,gBAAgBA,SAAQ,8BAA8B,EAAE,UAAU,EAAE,IAAI,CAAC;AAAA,IAC3E,EAAE;AAAA,EACJ,CAAC;AACH;AAGO,IAAM,YAA0B,QAAQ,WAAW,OAAO,MAAM;AACrE,QAAM,WAAW,MAAM,SAAS,CAAC;AACjC,QAAM,IAAI,eAAe;AACzB,MAAI,EAAE,IAAI,WAAW,SAAS,CAAC,EAAE,YAAY;AAC3C,QAAI,UAAU,CAAC,EAAG,QAAO,EAAE,KAAK,EAAE,QAAQ,+BAA+B,QAAQ,OAAO,GAAG,GAAG;AAC9F,UAAM,SAAS,WAAW,EAAE,IAAI,IAAI,QAAQ,sBAAsB,EAAE,CAAC;AACrE,UAAM,OAAO,WAAW,SAAS,IAAI,QAAQ,SAAS,SAAS,IAAI;AACnE,WAAO;AAAA,MACL,iBAAiB,SAAS,IAAI,QAAQ,SAAS,SAAS,IAAI;AAAA,MAC5D,mCAAmC,IAAI,oCAAoC,MAAM,KAAK,UAAU,CAAC,CAAC;AAAA,IACpG;AAAA,EACF;AACA,MAAI,EAAE,IAAI,WAAW,SAAS,EAAE,IAAI,WAAW,OAAQ,QAAO,EAAE,KAAK,sBAAsB,GAAG;AAC9F,QAAM,OAAO,EAAE,IAAI,WAAW,SAAS,MAAM,SAAS,CAAC,IAAI,CAAC;AAC5D,QAAM,WAAW,IAAI,KAAK,OAAO,KAAK,EAAE,IAAI,MAAM,SAAS,OAAO,YAAY,YAAY;AAC1F,MAAI,YAAY,aAAa,CAACC,SAAQ,CAAC,EAAE,iBAAiB;AACxD,UAAM,IAAI,gBAAgB,wCAAwC,KAAK,gBAAgB;AAAA,EACzF;AACA,QAAM,SAAS,MAAM,YAAY,GAAG,QAAQ,EAAE,aAAa,GAAG;AAAA,IAC5D,MAAM,IAAI,KAAK,IAAI,KAAK,EAAE,IAAI,MAAM,MAAM;AAAA,IAC1C,OAAO,EAAE,QAAQ;AAAA,EACnB,CAAC;AACD,MAAI,OAAO,SAAS,WAAY,QAAO,EAAE,SAAS,OAAO,KAAK,GAAG;AACjE,MAAI,OAAO,SAAS,QAAS,OAAM,OAAO;AAC1C,QAAM,IAAI;AAAA,IACR,OAAO,SAAS,SAAU,OAAO,WAAW,kBAAmB;AAAA,IAC/D;AAAA,EACF;AACF,CAAC;AAGM,IAAM,eAA6B,QAAQ,WAAW,OAAO,MAAM;AACxE,QAAM,WAAW,MAAM,SAAS,CAAC;AACjC,MAAI,CAAC,EAAE,IAAI,MAAM,MAAM,KAAK,CAAC,EAAE,IAAI,MAAM,OAAO,GAAG;AACjD,UAAM,IAAI,gBAAgB,oDAAoD,KAAK,cAAc;AAAA,EACnG;AACA,QAAM,SAAS,MAAM,YAAY,GAAG,QAAQ,EAAE,aAAa,GAAG,CAAC,CAAC;AAChE,MAAI,OAAO,SAAS,QAAS,OAAM,OAAO;AAC1C,MAAI,OAAO,SAAS,WAAW;AAC7B,UAAM,IAAI;AAAA,MACR,OAAO,SAAS,SAAU,OAAO,WAAW,kBAAmB;AAAA,MAC/D;AAAA,IACF;AAAA,EACF;AACA,QAAM,OAAO,OAAO;AAMpB,QAAM,QAAQ,WAAW,UAAU,KAAK,SAAS;AAAA,IAC/C,QAAQ,KAAK;AAAA,IACb,MAAM,KAAK;AAAA,IACX,SAAS,KAAK,OAAO,YAAY,YAAY,YAAY;AAAA,EAC3D,CAAC;AACD,SAAO,oBAAoB,GAAG,OAAO,SAAS;AAChD,CAAC;AAMM,IAAM,kBAAgC;AAAA,EAC3C,QAAQ,OAAO,OAAO,MAAM;AAC1B,QAAI,EAAE,IAAI,WAAW,OAAQ,QAAO,EAAE,KAAK,EAAE,QAAQ,qBAAqB,GAAG,GAAG;AAChF,gBAAY,CAAC;AACb,UAAM,WAAW,MAAM,SAAS,CAAC;AACjC,UAAM,OAAQ,MAAM,EAAE,IAAI,KAAK,EAAE,MAAM,OAAO,CAAC,EAAE;AACjD,UAAM,UAAU,IAAI,KAAK,QAAQ;AACjC,UAAM,cAAc,IAAI,KAAK,YAAY;AACzC,QAAI,CAAC,WAAW,CAAC;AACf,YAAM,IAAI,gBAAgB,kCAAkC,KAAK,eAAe;AAClF,QAAI;AACJ,QAAI;AACF,gBAAU,MAAM,SAAS,SAAS;AAAA,QAChC;AAAA,UACE,KAAK,SAAS;AAAA,UACd,KAAK,SAAS;AAAA,UACd,UAAU,SAAS;AAAA,UACnB,aAAa;AAAA,UACb,QAAQ,YAAY;AAAA,QACtB;AAAA,QACA,EAAE,SAAS,YAAY;AAAA,MACzB;AAAA,IACF,SAAS,KAAK;AACZ,YAAM,IAAI,gBAAiB,IAAc,WAAW,kBAAkB,KAAK,eAAe;AAAA,IAC5F;AACA,UAAM,QAAQ,WAAW,UAAU,SAAS;AAAA,MAC1C,QAAQ,cAAc,EAAE,aAAa,KAAK,CAAC,EAAE,IAAI;AAAA,MACjD,SAAS,IAAI,KAAK,OAAO,MAAM,YAAY,YAAY;AAAA,IACzD,CAAC;AACD,WAAO,oBAAoB,GAAG,OAAO,KAAK;AAAA,EAC5C,CAAC;AACH;AAGO,IAAM,oBAAkC;AAAA,EAC7C,QAAQ,OAAO,OAAO,MAAM;AAC1B,QAAI,EAAE,IAAI,WAAW,OAAQ,QAAO,EAAE,KAAK,EAAE,QAAQ,qBAAqB,GAAG,GAAG;AAChF,gBAAY,CAAC;AACb,UAAM,OAAQ,MAAM,EAAE,IAAI,KAAK,EAAE,MAAM,OAAO,CAAC,EAAE;AACjD,UAAM,OAAO,IAAI,KAAK,IAAI,IAAI,MAAM,gBAAgB,IAAI,KAAK,IAAI,CAAE,IAAI;AACvE,QAAI,CAAC;AACH,YAAM,IAAI,gBAAgB,wDAAwD,KAAK,cAAc;AACvG,WAAO,EAAE,KAAK,EAAE,GAAI,MAAMC,kBAAiB,IAAI,GAAI,MAAMC,UAAS,IAAI,EAAE,CAAC;AAAA,EAC3E,CAAC;AACH;AAGO,IAAM,aAA2B;AAAA,EACtC,CAAC,MAAO,UAAU,CAAC,IAAI,QAAQ;AAAA,EAC/B,OAAO,MAAM;AACX,UAAM,UAAU,MAAM,kBAAkB,CAAC;AACzC,QAAI,CAAC;AACH,YAAM,IAAI,gBAAgB,0CAA0C,KAAK,mBAAmB;AAC9F,UAAM,WAAW,MAAM,gBAAgB,QAAQ,GAAG;AAClD,QAAI,CAAC,SAAU,OAAM,IAAI,gBAAgB,yCAAyC,KAAK,kBAAkB;AACzG,UAAM,QAAQ,WAAW,UAAU,QAAQ,SAAS,EAAE,QAAQ,QAAQ,QAAQ,MAAM,QAAQ,KAAK,CAAC;AAClG,UAAM,OAAOC,cAAa;AAC1B,UAAM,KAAK,KAAK;AAChB,UAAM,KAAK,KAAK;AAChB,UAAM,OAAO,UAAU,CAAC;AACxB,UAAM,SAAS,CAACC,SAAgC,SAAmC,CAAC,GAAG,SAAS,QAAQ;AACtG,UAAI,MAAM;AACR,eAAO,EAAE;AAAA,UACP;AAAA,YACE,UAAU,QAAQ;AAAA,YAClB,SAAS;AAAA,cACP,OAAO,QAAQ,QAAQ;AAAA,cACvB,UAAU,QAAQ,QAAQ;AAAA,cAC1B,MAAM,QAAQ,QAAQ;AAAA,YACxB;AAAA,YACA,QAAQ,CAAC,GAAG,oBAAI,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;AAAA,YAC7B;AAAA,UACF;AAAA,UACA;AAAA,QACF;AAAA,MACF;AACA,YAAM,QAAQ,CAAC,MAAc,UAC3B,UAAU,WAAW,KAAK,CAAC,gBAAgB,WAAW,IAAI,CAAC,YAAY,WAAWA,QAAO,IAAI,KAAK,EAAE,CAAC,cAAc,OAAO,IAAI,KAAK,CAAC,GAAG,IAAI,CAAC,MAAM,kBAAkB,WAAW,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC;AACnM,YAAM,SAAS,OAAO,KAAK,MAAM,IAAI,OAAO,IAAI,MAAM,IAAI,UAAU,IAAI,MAAM,IAAI,OAAO;AACzF,aAAO;AAAA,QACL;AAAA,QACA,8BAA8B,WAAW,SAAS,IAAI,QAAQ,SAAS,SAAS,IAAI,CAAC,4BAA4B,UAAU,CAAC,CAAC,GAAG,MAAM;AAAA,QACtI;AAAA,MACF;AAAA,IACF;AACA,QAAI,EAAE,IAAI,WAAW,OAAO;AAC1B,aAAO,OAAO,EAAE,CAAC,EAAE,GAAG,QAAQ,QAAQ,YAAY,IAAI,CAAC,EAAE,GAAG,QAAQ,QAAQ,SAAS,GAAG,CAAC;AAAA,IAC3F;AACA,UAAM,OAAO,MAAM,SAAS,CAAC;AAC7B,UAAM,SAAS,EAAE,CAAC,EAAE,GAAG,OAAO,KAAK,EAAE,KAAK,EAAE,GAAG,CAAC,EAAE,GAAG,OAAO,KAAK,EAAE,KAAK,EAAE,EAAE;AAE5E,QAAI,OAAO,EAAE,KAAK,OAAO,EAAE,EAAE,YAAY,OAAO,QAAQ,QAAQ,SAAS,IAAI,YAAY;AACvF,YAAM,gBAAgB;AACxB,UAAM,SAAS,MAAM;AAAA,MACnB;AAAA,MACA;AAAA,MACA,EAAE,UAAU,OAAO,EAAE,GAAG,OAAO,OAAO,EAAE,EAAE;AAAA,MAC1C,OAAO,QAAQ;AAAA,IACjB;AACA,QAAI,kBAAkB,SAAU,QAAO,oBAAoB,GAAG,MAAM;AACpE,WAAO,OAAO,QAAQ,QAAQ,GAAG;AAAA,EACnC;AACF;AAGO,IAAM,kBAAgC;AAAA,EAC3C,CAAC,MAAO,UAAU,CAAC,IAAI,QAAQ;AAAA,EAC/B,OAAO,MAAM;AACX,UAAM,OAAOJ,SAAQ,CAAC;AACtB,QAAI,CAAC,KAAK;AACR,YAAM,IAAI,gBAAgB,6CAA6C,KAAK,gBAAgB;AAC9F,UAAM,WAAW,MAAM,cAAc,QAAQ,OAAO,EAAE,MAAM,KAAK,GAAG,CAAQ,EAAE,QAAQ,YAAY,IAAI;AACtG,QAAI,EAAE,IAAI,WAAW,QAAQ;AAC3B,YAAM,OAAO,MAAM,SAAS,CAAC;AAC7B,YAAM,KAAK,OAAO,KAAK,WAAW,EAAE;AACpC,YAAM,UAAU,SAAS,KAAK,CAAC,MAAM,OAAO,EAAE,EAAE,MAAM,EAAE;AACxD,UAAI,CAAC,QAAS,OAAM,IAAI,gBAAgB,8BAA8B,KAAK,WAAW;AACtF,YAAM,OAAOG,cAAa;AAC1B,YAAM,OAAO,MAAM,KAAK,QAAQ,OAAO,EAAE,IAAI,KAAK,GAAG,CAAQ,EAAE,MAAM;AACrE,UACE,SAAS,WAAW,KACpB,QACA,OAAQ,KAAa,sBAAsB,cAC3C,CAAE,KAAa,kBAAkB,GACjC;AACA,cAAM,IAAI;AAAA,UACR;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,MACF;AACA,YAAM,QAAQ,OAAO;AACrB,YAAM,qBAAqB,KAAK,eAAe,EAAE,GAAG,QAAQ,CAAC;AAC7D,UAAI,UAAU,CAAC,EAAG,QAAO,EAAE,KAAK,EAAE,cAAc,GAAG,CAAC;AACpD,aAAO,EAAE,SAAS,EAAE,IAAI,MAAM,GAAG;AAAA,IACnC;AACA,UAAM,OAAO,SAAS,IAAI,CAAC,OAAO;AAAA,MAChC,IAAI,EAAE;AAAA,MACN,UAAU,EAAE;AAAA,MACZ,KAAK,EAAE;AAAA,MACP,WAAW,EAAE;AAAA,MACb,YAAY,EAAE;AAAA,IAChB,EAAE;AACF,QAAI,UAAU,CAAC,EAAG,QAAO,EAAE,KAAK,EAAE,UAAU,KAAK,CAAC;AAClD,UAAM,OAAO,KACV;AAAA,MACC,CAAC,MACC,OAAO,WAAW,EAAE,QAAQ,CAAC,+CAA+C,UAAU,CAAC,CAAC,8CAA8C,WAAW,EAAE,EAAE,CAAC;AAAA,IAC1J,EACC,KAAK,EAAE;AACV,WAAO,KAAK,sBAAsB,OAAO,OAAO,IAAI,UAAU,+BAA+B;AAAA,EAC/F;AACF;AAMO,IAAM,aAAa,YAAY,QAAW;AAAA,EAC/C,KAAK,cAAc,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAAA,EACrE,KAAK,UAAU,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AAAA,EAC1E,KAAK,WAAW,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAAA,EAC5D,KAAK,gBAAgB,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAAA,EAC3E,KAAK,yBAAyB,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAAA,EACxE,KAAK,kCAAkC,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAAA,EACvF,KAAK,yBAAyB,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AACvF,CAAC;","names":["getUserModel","cache","reverse","tryGetContext","seal","unseal","OAuth2Strategy","ImproperlyConfigured","provider","g","provider","OAuth2Strategy","tryGetContext","seal","unseal","cache","getUserModel","provider","getUserModel","reverse","getUserModel","tokenPairForUser","getUser","reverse","userInfo","reverse","getUser","tokenPairForUser","userInfo","getUserModel","values"]}
|
|
1
|
+
{"version":3,"sources":["../src/adapter.ts","../src/settings.ts","../src/apps.ts","../src/migrations/index.ts","../src/migrations/0001_initial.ts","../src/login.ts","../src/signals.ts","../src/tokens.ts","../src/providers.ts","../src/resolve.ts","../src/views.ts"],"sourcesContent":["// The adapter (django-allauth's DefaultSocialAccountAdapter): override to customize signup and linking.\nimport { getUserModel } from '@ghuri/auth'\nimport { reverse } from '@ghuri/core'\nimport type { Context } from 'hono'\nimport type { SocialLogin } from './login'\nimport type { SocialAccount } from './models'\nimport { socialSettings } from './settings'\n\n/** Throw from `preSocialLogin()` to answer with your own response. */\nexport class ImmediateResponse extends Error {\n constructor(readonly response: Response) {\n super('ImmediateResponse')\n }\n}\n\nexport interface SignupData {\n username?: string\n email?: string\n}\n\nconst USERNAME_ALLOWED = /[^\\w.@+-]/g\n\nexport class SocialAccountAdapter {\n /** May new users sign up through social login? */\n isOpenForSignup(_c: Context, _login: SocialLogin): boolean | Promise<boolean> {\n return true\n }\n\n /** Called after the provider answered, before anything is looked up or created. */\n async preSocialLogin(_c: Context, _login: SocialLogin): Promise<void> {}\n\n /** May the user be created without showing the signup form? */\n isAutoSignupAllowed(_c: Context, login: SocialLogin): boolean | Promise<boolean> {\n const s = socialSettings()\n if (!s.autoSignup) return false\n if (s.emailRequired && !login.profile.email) return false\n return true\n }\n\n /** A new, unsaved user instance. */\n newUser(_c: Context, _login: SocialLogin): any {\n const User = getUserModel()\n return new (User as any)()\n }\n\n /** Copy profile data (and signup form data) onto the new user. */\n populateUser(_c: Context, login: SocialLogin, user: any, data: SignupData): any {\n const M = user.constructor as { USERNAME_FIELD: string; EMAIL_FIELD: string; _meta: any }\n const has = (f: string) => !!M._meta.getField?.(f)\n if (data.username !== undefined) user[M.USERNAME_FIELD] = data.username\n if (data.email !== undefined && has(M.EMAIL_FIELD)) user[M.EMAIL_FIELD] = data.email\n if (has('firstName') && login.profile.firstName) user.firstName = login.profile.firstName.slice(0, 150)\n if (has('lastName') && login.profile.lastName) user.lastName = login.profile.lastName.slice(0, 150)\n if (has('firstName') && !login.profile.firstName && login.profile.name && has('lastName')) {\n const [first, ...rest] = login.profile.name.trim().split(/\\s+/)\n user.firstName = (first ?? '').slice(0, 150)\n user.lastName = rest.join(' ').slice(0, 150)\n }\n return user\n }\n\n /** Save the new user (with an unusable password). */\n async saveUser(_c: Context, _login: SocialLogin, user: any): Promise<any> {\n if (typeof user.setUnusablePassword === 'function') user.setUnusablePassword()\n await user.save()\n return user\n }\n\n /** Username candidates, best first. */\n usernameCandidates(login: SocialLogin): string[] {\n const p = login.profile\n return [p.username, p.email?.split('@')[0], p.name, p.firstName, `${login.key}${p.id}`].filter(\n (v): v is string => typeof v === 'string' && v.trim().length > 0,\n )\n }\n\n /** A username that is free, from the profile. */\n async generateUsername(_c: Context, login: SocialLogin): Promise<string> {\n const User = getUserModel()\n const field = User.USERNAME_FIELD\n const maxLength = (User._meta.getField(field) as { maxLength?: number } | undefined)?.maxLength ?? 150\n const taken = async (name: string) => User.objects.filter({ [`${field}__iexact`]: name } as any).exists()\n for (const raw of this.usernameCandidates(login)) {\n const base = raw.trim().replace(/\\s+/g, '').replace(USERNAME_ALLOWED, '').slice(0, maxLength)\n if (!base) continue\n if (!(await taken(base))) return base\n for (let i = 2; i < 100; i++) {\n const suffix = String(i)\n const candidate = `${base.slice(0, maxLength - suffix.length)}${suffix}`\n if (!(await taken(candidate))) return candidate\n }\n }\n return `user${crypto.randomUUID().replace(/-/g, '').slice(0, 12)}`\n }\n\n /** Where to go after connecting an account. */\n getConnectRedirectUrl(_c: Context, _account: SocialAccount): string {\n try {\n return reverse('socialaccount_connections')\n } catch {\n return '/'\n }\n }\n\n /** Customize error responses; return undefined for the default. */\n authenticationError(\n _c: Context,\n _error: { provider: string; message: string; code?: string },\n ): Response | undefined | Promise<Response | undefined> {\n return undefined\n }\n}\n\nconst cache = new WeakMap<object, SocialAccountAdapter>()\nlet fallback: SocialAccountAdapter | undefined\n\nexport function getAdapter(): SocialAccountAdapter {\n const cls = socialSettings().adapter\n if (!cls) {\n fallback ??= new SocialAccountAdapter()\n return fallback\n }\n let a = cache.get(cls)\n if (!a) {\n a = new cls()\n cache.set(cls, a)\n }\n return a\n}\n","import { tryGetContext } from '@ghuri/core'\n\n/** Credentials of one provider app, as in settings (`PROVIDERS.github.APP`) or a `SocialApp` row. */\nexport interface AppSettings {\n clientId: string\n secret?: string\n key?: string\n /** For `openid_connect`: the id used in URLs (`/accounts/okta/login/`). */\n providerId?: string\n name?: string\n /** Provider-specific settings (`serverUrl` for OpenID Connect, `tenant` for Microsoft…). */\n settings?: Record<string, unknown>\n}\n\nexport interface ProviderSettings {\n APP?: AppSettings\n /** Several apps of one provider (`openid_connect`). */\n APPS?: AppSettings[]\n SCOPE?: string[]\n AUTH_PARAMS?: Record<string, string>\n /** Override whether this provider's emails count as verified. */\n VERIFIED_EMAIL?: boolean\n [key: string]: unknown\n}\n\nexport interface SocialAccountSettings {\n PROVIDERS?: Record<string, ProviderSettings>\n ADAPTER?: new () => import('./adapter').SocialAccountAdapter\n AUTO_SIGNUP?: boolean\n EMAIL_AUTHENTICATION?: boolean\n EMAIL_REQUIRED?: boolean\n LOGIN_ON_GET?: boolean\n STORE_TOKENS?: boolean\n LOGIN_RESPONSE?: 'session' | 'jwt'\n FRONTEND_URL?: string\n /** Where browser flows go on errors (default `LOGIN_URL`), with `?error=`. */\n LOGIN_ERROR_URL?: string\n}\n\nexport interface ResolvedSocialSettings {\n providers: Record<string, ProviderSettings>\n adapter?: new () => import('./adapter').SocialAccountAdapter\n autoSignup: boolean\n emailAuthentication: boolean\n emailRequired: boolean\n loginOnGet: boolean\n storeTokens: boolean\n loginResponse: 'session' | 'jwt'\n frontendUrl?: string\n loginErrorUrl: string\n}\n\nexport function socialSettings(): ResolvedSocialSettings {\n const settings = (tryGetContext()?.settings ?? {}) as Record<string, unknown>\n const s = (settings.SOCIALACCOUNT ?? {}) as SocialAccountSettings\n return {\n providers: s.PROVIDERS ?? {},\n adapter: s.ADAPTER,\n autoSignup: s.AUTO_SIGNUP ?? true,\n emailAuthentication: s.EMAIL_AUTHENTICATION ?? false,\n emailRequired: s.EMAIL_REQUIRED ?? false,\n loginOnGet: s.LOGIN_ON_GET ?? false,\n storeTokens: s.STORE_TOKENS ?? false,\n loginResponse: s.LOGIN_RESPONSE ?? 'session',\n frontendUrl: s.FRONTEND_URL,\n loginErrorUrl: s.LOGIN_ERROR_URL ?? (settings.LOGIN_URL as string | undefined) ?? '/accounts/login/',\n }\n}\n","import * as auth from '@ghuri/auth'\nimport { AppConfig, apps, ImproperlyConfigured } from '@ghuri/core'\nimport * as migrations from './migrations/index'\nimport { SocialAccount, SocialApp, SocialToken } from './models'\n\nfunction appPath(): string | undefined {\n const meta = import.meta as ImportMeta & { dirname?: string; filename?: string }\n const dir = meta.dirname\n if (!dir || !/[\\\\/]src$/.test(dir) || !/\\.[cm]?ts$/.test(meta.filename ?? '')) return undefined\n return dir\n}\n\nfunction migrationsModule(): Record<string, unknown> {\n const adapt = (auth as Record<string, any>).migrationsForUserModel\n return typeof adapt === 'function' ? adapt('socialaccount', migrations) : migrations\n}\n\n/** The `socialaccount` app (django-allauth's): `SocialApp`, `SocialAccount`, `SocialToken`. */\nexport class SocialAuthConfig extends AppConfig {\n name = '@ghuri/socialauth'\n override label = 'socialaccount'\n override verboseName = 'Social Accounts'\n override path = appPath()\n override migrations = migrationsModule()\n override models = { SocialApp, SocialAccount, SocialToken }\n\n override ready(): void {\n if (!apps.isInstalled('auth')) {\n throw new ImproperlyConfigured(\n \"'socialaccount' requires '@ghuri/auth': add AuthConfig (and ContentTypesConfig) to INSTALLED_APPS.\",\n )\n }\n }\n}\n","// Generated by Ghuri makemigrations: every migration of this app, in order. Do not edit.\nimport m0001_initial from './0001_initial'\n\nexport { m0001_initial }\n\n/** Every migration of this app by name, in order. */\nexport const migrations = {\n '0001_initial': m0001_initial,\n}\n","// Generated by Ghuri makemigrations on 2026-11-12 08:37\nimport { Migration, operations as ops } from '@ghuri/orm/migrations'\n\nexport default new Migration({\n initial: true,\n dependencies: [['auth', '0001_initial']],\n operations: [\n ops.CreateModel({\n name: 'SocialAccount',\n fields: {\n id: { type: 'BigAutoField', primaryKey: true },\n user: {\n type: 'ForeignKey',\n to: 'auth.User',\n onDelete: 'CASCADE',\n dbIndex: true,\n relatedName: 'socialAccounts',\n verboseName: 'user',\n },\n provider: { type: 'CharField', maxLength: 200, verboseName: 'provider' },\n uid: { type: 'CharField', maxLength: 191, verboseName: 'uid' },\n lastLogin: { type: 'DateTimeField', autoNow: true, verboseName: 'last login' },\n dateJoined: { type: 'DateTimeField', autoNowAdd: true, verboseName: 'date joined' },\n extraData: {\n type: 'JSONField',\n default: { callable: 'emptyDict' },\n verboseName: 'extra data',\n },\n },\n options: {\n dbTable: 'socialaccount_socialaccount',\n verboseName: 'social account',\n verboseNamePlural: 'social accounts',\n uniqueTogether: [['provider', 'uid']],\n },\n }),\n ops.CreateModel({\n name: 'SocialApp',\n fields: {\n id: { type: 'BigAutoField', primaryKey: true },\n provider: { type: 'CharField', maxLength: 30, verboseName: 'provider' },\n providerId: { type: 'CharField', maxLength: 200, blank: true, verboseName: 'provider ID' },\n name: { type: 'CharField', maxLength: 40, verboseName: 'name' },\n clientId: { type: 'CharField', maxLength: 191, verboseName: 'client id' },\n secret: { type: 'CharField', maxLength: 191, blank: true, verboseName: 'secret key' },\n key: { type: 'CharField', maxLength: 191, blank: true, verboseName: 'key' },\n settings: {\n type: 'JSONField',\n blank: true,\n default: { callable: 'emptyDict' },\n verboseName: 'settings',\n },\n },\n options: {\n dbTable: 'socialaccount_socialapp',\n verboseName: 'social application',\n verboseNamePlural: 'social applications',\n },\n }),\n ops.CreateModel({\n name: 'SocialToken',\n fields: {\n id: { type: 'BigAutoField', primaryKey: true },\n app: {\n type: 'ForeignKey',\n to: 'socialaccount.SocialApp',\n onDelete: 'CASCADE',\n null: true,\n blank: true,\n dbIndex: true,\n },\n account: {\n type: 'ForeignKey',\n to: 'socialaccount.SocialAccount',\n onDelete: 'CASCADE',\n dbIndex: true,\n relatedName: 'tokens',\n },\n token: { type: 'TextField', verboseName: 'token' },\n tokenSecret: { type: 'TextField', blank: true, verboseName: 'token secret' },\n expiresAt: { type: 'DateTimeField', null: true, blank: true, verboseName: 'expires at' },\n },\n options: {\n dbTable: 'socialaccount_socialtoken',\n verboseName: 'social application token',\n verboseNamePlural: 'social application tokens',\n uniqueTogether: [['app', 'account']],\n },\n }),\n ],\n})\n","// What happens after the provider answered: find or link the account, sign up, log in, respond.\nimport { login as authLogin, getUserModel, isSafeRedirect, tokenPairForUser } from '@ghuri/auth'\nimport { cache, getHost, getUser, isSecure, resolveUrl, reverse, tryGetContext } from '@ghuri/core'\nimport {\n loginBackendName,\n type OAuthTokens,\n type Profile,\n randomToken,\n seal,\n unseal,\n userInfo,\n} from '@ghuri/oauth'\nimport type { Context } from 'hono'\nimport { deleteCookie, getCookie, setCookie } from 'hono/cookie'\nimport { getAdapter, type SignupData } from './adapter'\nimport { SocialAccount } from './models'\nimport type { ResolvedProvider } from './resolve'\nimport { socialSettings } from './settings'\nimport { preSocialLogin, socialAccountAdded, socialAccountUpdated } from './signals'\nimport { storeTokens } from './tokens'\n\nexport type Process = 'login' | 'connect'\n/** `browser`: redirects (the OAuth callback); `api`: JSON (native tokens, SPA calls). */\nexport type Mode = 'browser' | 'api'\n\nexport interface SocialLogin extends ResolvedProvider {\n profile: Profile\n tokens?: OAuthTokens\n /** Whether the provider vouches for `profile.email`. */\n emailVerified: boolean\n process: Process\n next?: string\n}\n\nexport class SocialAuthError extends Error {\n constructor(\n message: string,\n readonly status = 400,\n readonly code = 'social_login_failed',\n ) {\n super(message)\n }\n}\n\nexport function buildLogin(\n resolved: ResolvedProvider,\n profile: Profile,\n opts: { tokens?: OAuthTokens; process?: Process; next?: string },\n): SocialLogin {\n return {\n ...resolved,\n profile: { ...profile, provider: resolved.key },\n tokens: opts.tokens,\n emailVerified: resolved.provider.emailVerified(profile, resolved.settings),\n process: opts.process ?? 'login',\n next: opts.next,\n }\n}\n\n// ---- responses ----\n\nfunction loginRedirectUrl(): string {\n return resolveUrl(\n (tryGetContext()?.settings.LOGIN_REDIRECT_URL as string | undefined) ?? '/accounts/profile/',\n )\n}\n\nconst CODE_PURPOSE = 'socialauth-code'\nconst CODE_TTL = 60\n\n/** A one-time code an SPA exchanges for a JWT pair at `token/` (tokens never travel in URLs). */\nexport async function makeLoginCode(user: any): Promise<string> {\n return seal(\n JSON.stringify({\n uid: String(user.pk),\n exp: Math.floor(Date.now() / 1000) + CODE_TTL,\n jti: randomToken(12),\n }),\n CODE_PURPOSE,\n )\n}\n\n/** The user of a login code, once (replays are refused while the cache remembers the code). */\nexport async function redeemLoginCode(code: string): Promise<any | null> {\n const raw = await unseal(code, CODE_PURPOSE)\n if (!raw) return null\n let data: { uid: string; exp: number; jti: string }\n try {\n data = JSON.parse(raw)\n } catch {\n return null\n }\n if (!data.exp || data.exp < Date.now() / 1000) return null\n const key = `ghuri:socialauth:code:${data.jti}`\n try {\n if (await cache.get(key)) return null\n await cache.set(key, 1, CODE_TTL * 2)\n } catch {\n // no cache configured: the 60-second expiry is the only replay limit\n }\n const User = getUserModel()\n const user = await User.objects.filter({ pk: User._meta.pk.toPython(data.uid) } as any).first()\n return user && (user as any).isActive !== false ? user : null\n}\n\n/** Log the user in and answer for the mode and `LOGIN_RESPONSE`. */\nexport async function finishLogin(c: Context, user: any, login: SocialLogin, mode: Mode): Promise<Response> {\n const s = socialSettings()\n if (user.isActive === false) throw new SocialAuthError('This account is inactive.', 403, 'inactive')\n if (s.loginResponse === 'jwt') {\n if (mode === 'api') return c.json({ ...(await tokenPairForUser(user)), user: userInfo(user) })\n if (!s.frontendUrl)\n throw new SocialAuthError('SOCIALACCOUNT.FRONTEND_URL is required with LOGIN_RESPONSE \"jwt\".', 500)\n return c.redirect(`${s.frontendUrl}#code=${encodeURIComponent(await makeLoginCode(user))}`, 302)\n }\n await authLogin(c, user, loginBackendName())\n if (mode === 'api') return c.json({ user: userInfo(user) })\n const next = login.next\n return c.redirect(isSafeRedirect(next, [getHost(c)]) ? next : loginRedirectUrl(), 302)\n}\n\n/** An error, answered as JSON (api) or a redirect to `LOGIN_ERROR_URL` / the frontend (browser). */\nexport async function errorResponse(\n c: Context,\n err: SocialAuthError,\n provider: string,\n mode: Mode,\n): Promise<Response> {\n const custom = await getAdapter().authenticationError(c, { provider, message: err.message, code: err.code })\n if (custom) return custom\n if (mode === 'api') return c.json({ detail: err.message, code: err.code }, err.status as 400)\n const s = socialSettings()\n if (s.loginResponse === 'jwt' && s.frontendUrl) {\n return c.redirect(`${s.frontendUrl}#error=${encodeURIComponent(err.message)}`, 302)\n }\n const url = new URL(s.loginErrorUrl, 'http://x')\n url.searchParams.set('error', err.message)\n return c.redirect(`${url.pathname}${url.search}`, 302)\n}\n\n// ---- pending signup (when the form is needed) ----\n\nconst SIGNUP_COOKIE = 'ghuri_social_signup'\nconst SIGNUP_PURPOSE = 'socialauth-signup'\nconst SIGNUP_TTL = 600\n\nexport interface PendingSignup {\n key: string\n profile: Profile\n tokens?: OAuthTokens\n emailVerified: boolean\n next?: string\n createdAt: number\n}\n\nexport async function savePendingSignup(c: Context, login: SocialLogin): Promise<void> {\n const pending: PendingSignup = {\n key: login.key,\n profile: login.profile,\n tokens: socialSettings().storeTokens ? login.tokens : undefined,\n emailVerified: login.emailVerified,\n next: login.next,\n createdAt: Date.now(),\n }\n setCookie(c, SIGNUP_COOKIE, await seal(JSON.stringify(pending), SIGNUP_PURPOSE), {\n path: '/',\n httpOnly: true,\n secure: isSecure(c),\n sameSite: 'Lax',\n maxAge: SIGNUP_TTL,\n })\n}\n\nexport async function readPendingSignup(c: Context): Promise<PendingSignup | null> {\n const raw = getCookie(c, SIGNUP_COOKIE)\n if (!raw) return null\n const json = await unseal(raw, SIGNUP_PURPOSE)\n if (!json) return null\n try {\n const p = JSON.parse(json) as PendingSignup\n return Date.now() - p.createdAt <= SIGNUP_TTL * 1000 ? p : null\n } catch {\n return null\n }\n}\n\nexport function clearPendingSignup(c: Context): void {\n deleteCookie(c, SIGNUP_COOKIE, { path: '/', secure: isSecure(c) })\n}\n\n/** Expire the pending-signup cookie on a response that was already built. */\nexport function expirePendingSignup(c: Context, res: Response): Response {\n res.headers.append(\n 'set-cookie',\n `${SIGNUP_COOKIE}=; Max-Age=0; Path=/; HttpOnly; SameSite=Lax${isSecure(c) ? '; Secure' : ''}`,\n )\n return res\n}\n\n// ---- the flow ----\n\nasync function emailTaken(email: string, exceptPk?: unknown): Promise<boolean> {\n const User = getUserModel()\n let qs = User.objects.filter({ [`${User.EMAIL_FIELD}__iexact`]: email } as any)\n if (exceptPk !== undefined) qs = qs.exclude({ pk: exceptPk } as any)\n return qs.exists()\n}\n\nasync function link(c: Context, login: SocialLogin, user: any): Promise<SocialAccount> {\n const account = await SocialAccount.objects.create({\n user,\n provider: login.key,\n uid: login.profile.id,\n extraData: login.profile.raw,\n } as any)\n await storeTokens(login, account)\n await socialAccountAdded.send(SocialAccount, { c, login, account })\n return account\n}\n\n/**\n * Create the user from the profile and the (optional) form data, link it, log in. Returns the problems instead\n * when the data is not acceptable.\n */\nexport async function signup(\n c: Context,\n login: SocialLogin,\n data: SignupData,\n mode: Mode,\n): Promise<Response | Record<string, string[]>> {\n const adapter = getAdapter()\n const User = getUserModel()\n const errors: Record<string, string[]> = {}\n const username = (data.username ?? '').trim()\n const email = (data.email ?? '').trim()\n if (User.USERNAME_FIELD !== User.EMAIL_FIELD) {\n if (!username) errors[User.USERNAME_FIELD] = ['This field is required.']\n else if (await User.objects.filter({ [`${User.USERNAME_FIELD}__iexact`]: username } as any).exists()) {\n errors[User.USERNAME_FIELD] = ['A user with that username already exists.']\n }\n }\n if (!email && (socialSettings().emailRequired || User.USERNAME_FIELD === User.EMAIL_FIELD)) {\n errors[User.EMAIL_FIELD] = ['This field is required.']\n } else if (email && (await emailTaken(email))) {\n errors[User.EMAIL_FIELD] = [\n `An account already uses this address. Log in to it first, then connect ${login.provider.name} from your account.`,\n ]\n }\n if (Object.keys(errors).length) return errors\n let user = adapter.newUser(c, login)\n user = adapter.populateUser(c, login, user, {\n username: User.USERNAME_FIELD === User.EMAIL_FIELD ? email : username,\n email: email || undefined,\n })\n user = await adapter.saveUser(c, login, user)\n await link(c, login, user)\n return finishLogin(c, user, login, mode)\n}\n\n/** Process a successful provider login (django-allauth's `complete_social_login`). */\nexport async function completeSocialLogin(c: Context, login: SocialLogin, mode: Mode): Promise<Response> {\n const adapter = getAdapter()\n await preSocialLogin.send(SocialAccount, { c, login })\n await adapter.preSocialLogin(c, login)\n const current = getUser(c)\n const User = getUserModel()\n\n // 1. A known link.\n const existing = await SocialAccount.objects.filter({ provider: login.key, uid: login.profile.id }).first()\n if (existing) {\n existing.extraData = login.profile.raw\n await existing.save()\n await storeTokens(login, existing)\n await socialAccountUpdated.send(SocialAccount, { c, login, account: existing })\n const userId = (existing as any).userId ?? (existing as any).user_id\n if (login.process === 'connect') {\n if (!current.isAuthenticated)\n throw new SocialAuthError('Log in before connecting an account.', 401, 'login_required')\n if (String(userId) !== String(current.pk)) {\n throw new SocialAuthError(\n `This ${login.provider.name} account is already connected to another user.`,\n 409,\n 'already_connected',\n )\n }\n return mode === 'api'\n ? c.json({ connected: true })\n : c.redirect(adapter.getConnectRedirectUrl(c, existing), 302)\n }\n const user = await User.objects.filter({ pk: userId } as any).first()\n if (!user) throw new SocialAuthError('The linked user no longer exists.', 401, 'user_missing')\n return finishLogin(c, user, login, mode)\n }\n\n // 2. Connecting to the logged-in user.\n if (login.process === 'connect') {\n if (!current.isAuthenticated)\n throw new SocialAuthError('Log in before connecting an account.', 401, 'login_required')\n const user = await User.objects.filter({ pk: current.pk } as any).first()\n const account = await link(c, login, user)\n return mode === 'api'\n ? c.json({ connected: true })\n : c.redirect(adapter.getConnectRedirectUrl(c, account), 302)\n }\n\n // 3. A verified email that belongs to exactly one user.\n const s = socialSettings()\n if (s.emailAuthentication && login.emailVerified && login.profile.email) {\n const matches = await User.objects\n .filter({ [`${User.EMAIL_FIELD}__iexact`]: login.profile.email } as any)\n .limit(2)\n if (matches.length === 1) {\n await link(c, login, matches[0])\n return finishLogin(c, matches[0], login, mode)\n }\n }\n\n // 4. Sign up.\n if (!(await adapter.isOpenForSignup(c, login))) {\n throw new SocialAuthError('Sign-ups are closed.', 403, 'signup_closed')\n }\n if (await adapter.isAutoSignupAllowed(c, login)) {\n const email =\n login.profile.email && !(await emailTaken(login.profile.email)) ? login.profile.email : undefined\n if (email || (!s.emailRequired && !login.profile.email && User.USERNAME_FIELD !== User.EMAIL_FIELD)) {\n const result = await signup(\n c,\n login,\n {\n username:\n User.USERNAME_FIELD === User.EMAIL_FIELD ? email : await adapter.generateUsername(c, login),\n email,\n },\n mode,\n )\n if (result instanceof Response) return result\n }\n }\n await savePendingSignup(c, login)\n let signupUrl = '/accounts/signup/'\n try {\n signupUrl = reverse('socialaccount_signup')\n } catch {\n // not routed by name\n }\n if (mode === 'api') {\n return c.json({ detail: 'Finish signing up.', code: 'signup_required', signupUrl }, 409)\n }\n return c.redirect(signupUrl, 302)\n}\n","import { Signal } from '@ghuri/core'\nimport type { Context } from 'hono'\nimport type { SocialLogin } from './login'\nimport type { SocialAccount } from './models'\n\nconst g = globalThis as any\nfunction singleton<T>(key: string, make: () => T): T {\n const k = Symbol.for(key)\n if (!g[k]) g[k] = make()\n return g[k]\n}\n\n/** Before a social login is processed (after the provider answered). */\nexport const preSocialLogin: Signal<{ c: Context; login: SocialLogin }> = singleton(\n 'ghuri.socialauth.preSocialLogin',\n () => new Signal('preSocialLogin'),\n)\n/** A provider account was linked to a user (signup or connect). */\nexport const socialAccountAdded: Signal<{ c: Context; login: SocialLogin; account: SocialAccount }> =\n singleton('ghuri.socialauth.socialAccountAdded', () => new Signal('socialAccountAdded'))\n/** An existing link logged in again (profile and tokens refreshed). */\nexport const socialAccountUpdated: Signal<{ c: Context; login: SocialLogin; account: SocialAccount }> =\n singleton('ghuri.socialauth.socialAccountUpdated', () => new Signal('socialAccountUpdated'))\n/** A link was removed from the connections page. */\nexport const socialAccountRemoved: Signal<{ c: Context; account: SocialAccount }> = singleton(\n 'ghuri.socialauth.socialAccountRemoved',\n () => new Signal('socialAccountRemoved'),\n)\n","// Provider tokens (STORE_TOKENS), encrypted at rest with a key derived from SECRET_KEY.\nimport { OAuth2Strategy, type OAuthTokens, seal, unseal } from '@ghuri/oauth'\nimport type { SocialLogin } from './login'\nimport { type SocialAccount, SocialToken } from './models'\nimport { resolveProvider } from './resolve'\nimport { socialSettings } from './settings'\n\nconst PURPOSE = 'socialauth-token'\n\nexport async function storeTokens(login: SocialLogin, account: SocialAccount): Promise<void> {\n if (!socialSettings().storeTokens || !login.tokens?.accessToken) return\n const t = login.tokens\n const app = login.row ?? null\n const existing = await SocialToken.objects.filter({ account, app } as any).first()\n const values = {\n token: await seal(t.accessToken, PURPOSE),\n tokenSecret: t.refreshToken ? await seal(t.refreshToken, PURPOSE) : (existing?.tokenSecret ?? ''),\n expiresAt: t.expiresAt ? new Date(t.expiresAt) : null,\n }\n if (existing) {\n Object.assign(existing, values)\n await existing.save()\n } else {\n await SocialToken.objects.create({ account, app, ...values } as any)\n }\n}\n\n/**\n * A usable access token for the account (refreshed with the stored refresh token when it expired), or null\n * when tokens are not stored or cannot be refreshed.\n */\nexport async function getAccessToken(account: SocialAccount): Promise<string | null> {\n const row = await SocialToken.objects.filter({ account } as any).first()\n if (!row) return null\n const access = await unseal(row.token, PURPOSE)\n const expiresAt = row.expiresAt ? new Date(row.expiresAt as any).getTime() : undefined\n if (access && (!expiresAt || expiresAt - 30_000 > Date.now())) return access\n const refresh = row.tokenSecret ? await unseal(row.tokenSecret, PURPOSE) : null\n if (!refresh) return null\n const resolved = await resolveProvider(account.provider)\n if (!resolved) return null\n const strategy = resolved.provider.createStrategy({\n key: resolved.key,\n app: resolved.app,\n settings: resolved.settings,\n callbackURL: '/',\n verify: async () => null,\n })\n if (!(strategy instanceof OAuth2Strategy)) return null\n let tokens: OAuthTokens\n try {\n tokens = await (await strategy.client()).refresh(refresh)\n } catch {\n return null\n }\n row.token = await seal(tokens.accessToken, PURPOSE)\n if (tokens.refreshToken) row.tokenSecret = await seal(tokens.refreshToken, PURPOSE)\n row.expiresAt = (tokens.expiresAt ? new Date(tokens.expiresAt) : null) as any\n await row.save()\n return tokens.accessToken\n}\n","// The provider catalog: each provider turns app credentials into an @ghuri/oauth strategy and knows how far to\n// trust its profile (is the email verified?).\n\nimport { ImproperlyConfigured } from '@ghuri/core'\nimport {\n getJson,\n OAuth2Strategy,\n OAuthError,\n OIDCStrategy,\n type Profile,\n profileFromClaims,\n providerFetch,\n type VerifyFunction,\n} from '@ghuri/oauth'\nimport type { AppSettings, ProviderSettings } from './settings'\n\nexport interface StrategyContext {\n /** The id used in URLs and stored on `SocialAccount.provider` (`github`, or an OIDC app's `providerId`). */\n key: string\n app: AppSettings\n settings: ProviderSettings\n callbackURL: string\n verify: VerifyFunction\n}\n\nexport abstract class Provider {\n abstract readonly id: string\n abstract readonly name: string\n /** Several apps per provider, each with its own `providerId` (OpenID Connect). */\n readonly multipleApps: boolean = false\n /** Default scopes when `SCOPE` is not set. */\n readonly defaultScope: string[] = []\n\n abstract createStrategy(ctx: StrategyContext): OAuth2Strategy\n\n scope(settings: ProviderSettings): string[] {\n return settings.SCOPE ?? this.defaultScope\n }\n\n /** May this provider's email be trusted to belong to the user? */\n emailVerified(profile: Profile, settings: ProviderSettings): boolean {\n if (settings.VERIFIED_EMAIL !== undefined) return settings.VERIFIED_EMAIL && !!profile.email\n return profile.emailVerified === true && !!profile.email\n }\n\n /**\n * Native / mobile login: verify a token the app obtained with the provider's own SDK and return the profile.\n * The token must have been issued to one of our client ids. Default: ID tokens of OpenID Connect providers.\n */\n async verifyNativeToken(\n ctx: StrategyContext,\n tokens: { accessToken?: string; idToken?: string },\n ): Promise<Profile> {\n const strategy = this.createStrategy(ctx)\n if (!(strategy instanceof OIDCStrategy) || !tokens.idToken) {\n throw new OAuthError(`${this.name} login with a native token needs an id_token.`, 'unsupported')\n }\n const audiences = [ctx.app.clientId, ...((ctx.app.settings?.audiences as string[] | undefined) ?? [])]\n let claims: Record<string, any> | undefined\n let lastError: unknown\n for (const aud of audiences) {\n try {\n const s = this.createStrategy({ ...ctx, app: { ...ctx.app, clientId: aud } }) as OIDCStrategy\n claims = await s.validateIdToken(tokens.idToken)\n break\n } catch (err) {\n lastError = err\n }\n }\n if (!claims)\n throw lastError instanceof Error\n ? new OAuthError(lastError.message, 'invalid_token')\n : new OAuthError('Invalid ID token.')\n return this.profileFromClaims(ctx.key, claims)\n }\n\n profileFromClaims(key: string, claims: Record<string, any>): Profile {\n return profileFromClaims(key, claims)\n }\n}\n\nfunction common(ctx: StrategyContext, provider: Provider) {\n return {\n name: ctx.key,\n clientId: ctx.app.clientId,\n clientSecret: ctx.app.secret,\n callbackURL: ctx.callbackURL,\n scope: provider.scope(ctx.settings),\n authorizationParams: ctx.settings.AUTH_PARAMS,\n }\n}\n\n/** An OIDC strategy whose profile goes through the provider's own claim mapping. */\nfunction oidc(\n ctx: StrategyContext,\n provider: Provider,\n issuer: string,\n extra: Record<string, unknown> = {},\n): OIDCStrategy {\n return new OIDCStrategy(\n {\n ...common(ctx, provider),\n issuer,\n profile: async (tokens) =>\n provider.profileFromClaims(ctx.key, (tokens.raw as { claims: Record<string, any> }).claims),\n ...extra,\n },\n ctx.verify,\n )\n}\n\n// ---- GitHub ----\n\nexport class GitHubProvider extends Provider {\n readonly id = 'github'\n readonly name = 'GitHub'\n override readonly defaultScope = ['read:user', 'user:email']\n\n private api(ctx: StrategyContext): string {\n return String(ctx.app.settings?.apiUrl ?? 'https://api.github.com').replace(/\\/+$/, '')\n }\n\n createStrategy(ctx: StrategyContext): OAuth2Strategy {\n const web = String(ctx.app.settings?.webUrl ?? 'https://github.com').replace(/\\/+$/, '')\n const api = this.api(ctx)\n return new OAuth2Strategy(\n {\n ...common(ctx, this),\n authorizationURL: `${web}/login/oauth/authorize`,\n tokenURL: `${web}/login/oauth/access_token`,\n profile: async (_tokens, p) => this.profile(ctx.key, api, (url) => p.getJsonAuthed(url)),\n },\n ctx.verify,\n )\n }\n\n private async profile(key: string, api: string, get: (url: string) => Promise<any>): Promise<Profile> {\n const user = await get(`${api}/user`)\n let email: string | undefined = user.email ?? undefined\n let verified = false\n try {\n const emails = (await get(`${api}/user/emails`)) as unknown as Array<{\n email: string\n primary: boolean\n verified: boolean\n }>\n const list = Array.isArray(emails) ? emails : []\n const primary = list.find((e) => e.primary && e.verified) ?? list.find((e) => e.verified)\n if (primary) {\n email = primary.email\n verified = true\n }\n } catch {\n // no user:email scope\n }\n return {\n provider: key,\n id: String(user.id),\n username: user.login,\n name: user.name ?? undefined,\n email,\n emailVerified: verified,\n avatarUrl: user.avatar_url,\n raw: user,\n }\n }\n\n /** Checks with GitHub that the token belongs to our OAuth app (`POST /applications/{client_id}/token`). */\n override async verifyNativeToken(ctx: StrategyContext, tokens: { accessToken?: string }): Promise<Profile> {\n if (!tokens.accessToken)\n throw new OAuthError('GitHub login with a native token needs an access_token.', 'unsupported')\n const api = this.api(ctx)\n const res = await providerFetch(`${api}/applications/${encodeURIComponent(ctx.app.clientId)}/token`, {\n method: 'POST',\n headers: {\n authorization: `Basic ${btoa(`${ctx.app.clientId}:${ctx.app.secret ?? ''}`)}`,\n accept: 'application/vnd.github+json',\n 'content-type': 'application/json',\n },\n body: JSON.stringify({ access_token: tokens.accessToken }),\n })\n if (!res.ok) throw new OAuthError('GitHub did not accept the access token for this app.', 'invalid_token')\n const headers = { authorization: `Bearer ${tokens.accessToken}` }\n return this.profile(ctx.key, api, (url) => getJson(url, { headers }))\n }\n}\n\n// ---- Google ----\n\nexport class GoogleProvider extends Provider {\n readonly id = 'google'\n readonly name = 'Google'\n override readonly defaultScope = ['openid', 'email', 'profile']\n\n createStrategy(ctx: StrategyContext): OAuth2Strategy {\n return oidc(ctx, this, 'https://accounts.google.com')\n }\n}\n\n// ---- Facebook ----\n\nexport class FacebookProvider extends Provider {\n readonly id = 'facebook'\n readonly name = 'Facebook'\n override readonly defaultScope = ['email', 'public_profile']\n\n private graph(ctx: StrategyContext): string {\n return `https://graph.facebook.com/${String(ctx.settings.VERSION ?? ctx.app.settings?.version ?? 'v21.0')}`\n }\n\n createStrategy(ctx: StrategyContext): OAuth2Strategy {\n const version = String(ctx.settings.VERSION ?? ctx.app.settings?.version ?? 'v21.0')\n const graph = this.graph(ctx)\n return new OAuth2Strategy(\n {\n ...common(ctx, this),\n scopeSeparator: ',',\n authorizationURL: `https://www.facebook.com/${version}/dialog/oauth`,\n tokenURL: `${graph}/oauth/access_token`,\n profile: async (_t, p) =>\n this.profile(\n ctx.key,\n await p.getJsonAuthed(`${graph}/me?fields=id,name,email,first_name,last_name,picture`),\n ),\n },\n ctx.verify,\n )\n }\n\n private profile(key: string, me: Record<string, any>): Profile {\n return {\n provider: key,\n id: String(me.id),\n name: me.name,\n firstName: me.first_name,\n lastName: me.last_name,\n email: me.email,\n // Facebook does not say whether the address was confirmed: unverified unless VERIFIED_EMAIL.\n emailVerified: false,\n avatarUrl: me.picture?.data?.url,\n raw: me,\n }\n }\n\n /** Checks the token with `debug_token` (issued to our app id) before trusting it. */\n override async verifyNativeToken(ctx: StrategyContext, tokens: { accessToken?: string }): Promise<Profile> {\n if (!tokens.accessToken)\n throw new OAuthError('Facebook login with a native token needs an access_token.', 'unsupported')\n const graph = this.graph(ctx)\n const appToken = `${ctx.app.clientId}|${ctx.app.secret ?? ''}`\n const debug = await getJson(\n `${graph}/debug_token?input_token=${encodeURIComponent(tokens.accessToken)}&access_token=${encodeURIComponent(appToken)}`,\n )\n if (!debug.data?.is_valid || String(debug.data.app_id) !== ctx.app.clientId) {\n throw new OAuthError('The Facebook token was not issued to this app.', 'invalid_token')\n }\n const me = await getJson(`${graph}/me?fields=id,name,email,first_name,last_name,picture`, {\n headers: { authorization: `Bearer ${tokens.accessToken}` },\n })\n return this.profile(ctx.key, me)\n }\n}\n\n// ---- Microsoft (Entra ID) ----\n\nexport class MicrosoftProvider extends Provider {\n readonly id = 'microsoft'\n readonly name = 'Microsoft'\n override readonly defaultScope = ['openid', 'email', 'profile', 'User.Read']\n\n createStrategy(ctx: StrategyContext): OAuth2Strategy {\n const tenant = String(ctx.app.settings?.tenant ?? ctx.settings.TENANT ?? 'common')\n const multi = ['common', 'organizations', 'consumers'].includes(tenant)\n return oidc(ctx, this, `https://login.microsoftonline.com/${tenant}/v2.0`, {\n // Multi-tenant endpoints publish `{tenantid}` in their issuer; accept any tenant's issuer.\n issuerValidation: multi\n ? (iss: string) => /^https:\\/\\/login\\.microsoftonline\\.com\\/[0-9a-f-]{36}\\/v2\\.0$/.test(iss)\n : undefined,\n fetchUserInfo: false,\n })\n }\n\n override profileFromClaims(key: string, claims: Record<string, any>): Profile {\n const p = profileFromClaims(key, claims)\n // Entra ID emails are not verified by Microsoft (tenants can set any address): never trust them by default.\n return { ...p, id: String(claims.oid ?? claims.sub), emailVerified: false }\n }\n\n override emailVerified(profile: Profile, settings: ProviderSettings): boolean {\n return settings.VERIFIED_EMAIL === true && !!profile.email\n }\n}\n\n// ---- Discord ----\n\nexport class DiscordProvider extends Provider {\n readonly id = 'discord'\n readonly name = 'Discord'\n override readonly defaultScope = ['identify', 'email']\n\n createStrategy(ctx: StrategyContext): OAuth2Strategy {\n return new OAuth2Strategy(\n {\n ...common(ctx, this),\n authorizationURL: 'https://discord.com/oauth2/authorize',\n tokenURL: 'https://discord.com/api/oauth2/token',\n profile: async (_t, p) => {\n const me = await p.getJsonAuthed('https://discord.com/api/users/@me')\n return {\n provider: ctx.key,\n id: String(me.id),\n username: me.username,\n name: me.global_name ?? me.username,\n email: me.email ?? undefined,\n emailVerified: me.verified === true,\n avatarUrl: me.avatar ? `https://cdn.discordapp.com/avatars/${me.id}/${me.avatar}.png` : undefined,\n raw: me,\n }\n },\n },\n ctx.verify,\n )\n }\n\n override async verifyNativeToken(): Promise<Profile> {\n throw new OAuthError(\n 'Discord tokens cannot be checked against a client id; use the redirect flow.',\n 'unsupported',\n )\n }\n}\n\n// ---- GitLab (gitlab.com or self-hosted) ----\n\nexport class GitLabProvider extends Provider {\n readonly id = 'gitlab'\n readonly name = 'GitLab'\n override readonly defaultScope = ['openid', 'email', 'profile']\n\n createStrategy(ctx: StrategyContext): OAuth2Strategy {\n const url = String(ctx.app.settings?.url ?? ctx.settings.GITLAB_URL ?? 'https://gitlab.com').replace(\n /\\/+$/,\n '',\n )\n return oidc(ctx, this, url)\n }\n\n override profileFromClaims(key: string, claims: Record<string, any>): Profile {\n return { ...profileFromClaims(key, claims), username: claims.nickname ?? claims.preferred_username }\n }\n}\n\n// ---- Any OpenID Connect issuer ----\n\nexport class OpenIDConnectProvider extends Provider {\n readonly id = 'openid_connect'\n readonly name = 'OpenID Connect'\n override readonly multipleApps = true\n override readonly defaultScope = ['openid', 'email', 'profile']\n\n createStrategy(ctx: StrategyContext): OAuth2Strategy {\n const issuer = ctx.app.settings?.serverUrl ?? ctx.app.settings?.server_url\n if (typeof issuer !== 'string') {\n throw new ImproperlyConfigured(\n `The OpenID Connect app '${ctx.key}' needs settings.serverUrl (the issuer).`,\n )\n }\n return oidc(ctx, this, issuer)\n }\n}\n\n// ---- registry ----\n\nconst KEY = Symbol.for('ghuri.socialauth.providers')\nconst registry: Map<string, Provider> = (() => {\n const g = globalThis as any\n if (!g[KEY]) {\n const m = new Map<string, Provider>()\n for (const p of [\n new GitHubProvider(),\n new GoogleProvider(),\n new FacebookProvider(),\n new MicrosoftProvider(),\n new DiscordProvider(),\n new GitLabProvider(),\n new OpenIDConnectProvider(),\n ]) {\n m.set(p.id, p)\n }\n g[KEY] = m\n }\n return g[KEY]\n})()\n\n/** Add (or replace) a provider: `registerProvider(new MyProvider())`. */\nexport function registerProvider(provider: Provider): void {\n registry.set(provider.id, provider)\n}\n\nexport function getProvider(id: string): Provider | undefined {\n return registry.get(id)\n}\n\nexport function allProviders(): Provider[] {\n return [...registry.values()]\n}\n","// Which providers are configured, and with which app credentials (settings first, then SocialApp rows).\n\nimport { SocialApp } from './models'\nimport { allProviders, getProvider, type Provider } from './providers'\nimport { type AppSettings, type ProviderSettings, socialSettings } from './settings'\n\nexport interface ResolvedProvider {\n /** The id in URLs and on `SocialAccount.provider`. */\n key: string\n provider: Provider\n app: AppSettings\n settings: ProviderSettings\n /** The `SocialApp` row, when the credentials came from the database. */\n row?: SocialApp\n}\n\nfunction fromRow(row: SocialApp): AppSettings {\n return {\n clientId: row.clientId,\n secret: row.secret || undefined,\n key: row.key || undefined,\n providerId: row.providerId || undefined,\n name: row.name,\n settings: (row.settings as Record<string, unknown>) ?? {},\n }\n}\n\nasync function safeRows(filter: Record<string, unknown>): Promise<SocialApp[]> {\n try {\n return await SocialApp.objects.filter(filter).orderBy('id')\n } catch {\n return [] // table not migrated yet\n }\n}\n\n/** The provider for `key` (`github`, or the `providerId` of a multi-app provider), or null if not configured. */\nexport async function resolveProvider(key: string): Promise<ResolvedProvider | null> {\n const all = socialSettings().providers\n const direct = getProvider(key)\n if (direct && !direct.multipleApps) {\n const settings = all[key] ?? {}\n if (settings.APP) return { key, provider: direct, app: settings.APP, settings }\n const [row] = await safeRows({ provider: key })\n return row ? { key, provider: direct, app: fromRow(row), settings, row } : null\n }\n for (const provider of allProviders().filter((p) => p.multipleApps)) {\n const settings = all[provider.id] ?? {}\n const app = settings.APPS?.find((a) => a.providerId === key)\n if (app) return { key, provider, app, settings }\n const [row] = await safeRows({ provider: provider.id, providerId: key })\n if (row) return { key, provider, app: fromRow(row), settings, row }\n }\n return null\n}\n\n/** Every configured provider (for login buttons). */\nexport async function configuredProviders(): Promise<ResolvedProvider[]> {\n const all = socialSettings().providers\n const out: ResolvedProvider[] = []\n const seen = new Set<string>()\n for (const provider of allProviders()) {\n const settings = all[provider.id] ?? {}\n if (provider.multipleApps) {\n for (const app of settings.APPS ?? []) {\n if (app.providerId && !seen.has(app.providerId)) {\n seen.add(app.providerId)\n out.push({ key: app.providerId, provider, app, settings })\n }\n }\n for (const row of await safeRows({ provider: provider.id })) {\n if (row.providerId && !seen.has(row.providerId)) {\n seen.add(row.providerId)\n out.push({ key: row.providerId, provider, app: fromRow(row), settings, row })\n }\n }\n } else if (settings.APP) {\n seen.add(provider.id)\n out.push({ key: provider.id, provider, app: settings.APP, settings })\n }\n }\n for (const row of await safeRows({})) {\n const provider = getProvider(row.provider)\n if (provider && !provider.multipleApps && !seen.has(row.provider)) {\n seen.add(row.provider)\n out.push({ key: row.provider, provider, app: fromRow(row), settings: all[row.provider] ?? {}, row })\n }\n }\n return out\n}\n","// URLs and views: providers list, login start, callback, native tokens, SPA code exchange, signup, connections.\nimport { getUserModel, readData, tokenPairForUser } from '@ghuri/auth'\nimport {\n csrfExempt,\n escapeHtml,\n getCsrfToken,\n getUser,\n path,\n reverse,\n urlpatterns,\n type ViewFunction,\n wantsJson,\n} from '@ghuri/core'\nimport { type OAuthTokens, type Profile, userInfo } from '@ghuri/oauth'\nimport type { Context } from 'hono'\nimport { ImmediateResponse } from './adapter'\nimport {\n buildLogin,\n completeSocialLogin,\n errorResponse,\n expirePendingSignup,\n type Mode,\n type Process,\n readPendingSignup,\n redeemLoginCode,\n SocialAuthError,\n signup,\n} from './login'\nimport { SocialAccount } from './models'\nimport { configuredProviders, type ResolvedProvider, resolveProvider } from './resolve'\nimport { socialSettings } from './settings'\nimport { socialAccountRemoved } from './signals'\n\nfunction page(title: string, body: string, status = 200): Response {\n const html = `<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\"><title>${escapeHtml(title)}</title><style>body{font:16px/1.5 system-ui,sans-serif;max-width:28rem;margin:4rem auto;padding:0 1rem}button{font:inherit;padding:.5rem 1rem;cursor:pointer}input{font:inherit;width:100%;padding:.4rem;margin:.2rem 0 .8rem;box-sizing:border-box}.err{color:#b91c1c}</style></head><body><h1>${escapeHtml(title)}</h1>${body}</body></html>`\n return new Response(html, { status, headers: { 'content-type': 'text/html; charset=utf-8' } })\n}\n\nfunction csrfInput(c: Context): string {\n try {\n return `<input type=\"hidden\" name=\"csrfmiddlewaretoken\" value=\"${escapeHtml(getCsrfToken(c))}\">`\n } catch {\n return ''\n }\n}\n\nfunction str(v: unknown): string | undefined {\n return typeof v === 'string' && v ? v : undefined\n}\n\nasync function provider(c: Context): Promise<ResolvedProvider> {\n const key = c.req.param('provider') ?? ''\n const resolved = await resolveProvider(key)\n if (!resolved)\n throw new SocialAuthError(`Unknown or unconfigured provider '${key}'.`, 404, 'unknown_provider')\n return resolved\n}\n\nfunction strategyFor(c: Context, resolved: ResolvedProvider) {\n const callbackURL = c.req.path.replace(/login\\/(callback\\/)?$/, 'login/callback/')\n const override = (globalThis as any)[Symbol.for('ghuri.socialauth.testStrategy')] as\n | ((key: string, callbackURL: string) => import('@ghuri/oauth').Strategy | undefined)\n | undefined\n const fake = override?.(resolved.key, callbackURL)\n if (fake) return fake\n return resolved.provider.createStrategy({\n key: resolved.key,\n app: resolved.app,\n settings: resolved.settings,\n callbackURL,\n // The social flow decides what happens next; the strategy only has to succeed.\n verify: async () => ({ socialLogin: true }),\n })\n}\n\n/** Run a handler, turning SocialAuthError / ImmediateResponse into responses. */\nfunction guarded(mode: Mode | ((c: Context) => Mode), fn: (c: Context) => Promise<Response>): ViewFunction {\n return async (c) => {\n const m = typeof mode === 'function' ? mode(c) : mode\n try {\n return await fn(c)\n } catch (err) {\n if (err instanceof ImmediateResponse) return err.response\n if (err instanceof SocialAuthError) return errorResponse(c, err, c.req.param('provider') ?? '', m)\n throw err\n }\n }\n}\n\n/** JSON only: refuses cross-site form posts to the CSRF-exempt API endpoints (they can't send JSON). */\nfunction requireJson(c: Context): void {\n if (!(c.req.header('content-type') ?? '').includes('application/json')) {\n throw new SocialAuthError('Send a JSON body (Content-Type: application/json).', 415, 'json_required')\n }\n}\n\n// ---- views ----\n\n/** `GET providers/`: configured providers with their login URLs (for SPA buttons). */\nexport const providersView: ViewFunction = async (c) => {\n const list = await configuredProviders()\n return c.json({\n providers: list.map((p) => ({\n id: p.key,\n name: p.app.name ?? p.provider.name,\n provider: p.provider.id,\n loginUrl: reverse('socialaccount_login', { provider: p.key }),\n nativeTokenUrl: reverse('socialaccount_native_token', { provider: p.key }),\n })),\n })\n}\n\n/** `<provider>/login/`: POST starts the flow; GET confirms first (unless LOGIN_ON_GET). */\nexport const loginView: ViewFunction = guarded('browser', async (c) => {\n const resolved = await provider(c)\n const s = socialSettings()\n if (c.req.method === 'GET' && !s.loginOnGet) {\n if (wantsJson(c)) return c.json({ detail: 'POST to this URL to log in.', method: 'POST' }, 405)\n const action = escapeHtml(c.req.url.replace(/^[a-z]+:\\/\\/[^/]+/i, ''))\n const name = escapeHtml(resolved.app.name ?? resolved.provider.name)\n return page(\n `Continue with ${resolved.app.name ?? resolved.provider.name}`,\n `<p>You are about to log in with ${name}.</p><form method=\"post\" action=\"${action}\">${csrfInput(c)}<button type=\"submit\">Continue</button></form>`,\n )\n }\n if (c.req.method !== 'GET' && c.req.method !== 'POST') return c.text('Method not allowed', 405)\n const data = c.req.method === 'POST' ? await readData(c) : {}\n const process = (str(data.process) ?? c.req.query('process')) === 'connect' ? 'connect' : 'login'\n if (process === 'connect' && !getUser(c).isAuthenticated) {\n throw new SocialAuthError('Log in before connecting an account.', 401, 'login_required')\n }\n const result = await strategyFor(c, resolved).authenticate(c, {\n next: str(data.next) ?? c.req.query('next'),\n state: { process },\n })\n if (result.type === 'redirect') return c.redirect(result.url, 302)\n if (result.type === 'error') throw result.error\n throw new SocialAuthError(\n result.type === 'fail' ? (result.message ?? 'Login failed.') : 'Login failed.',\n 400,\n )\n})\n\n/** `<provider>/login/callback/`: the provider sends the browser back here. */\nexport const callbackView: ViewFunction = guarded('browser', async (c) => {\n const resolved = await provider(c)\n if (!c.req.query('code') && !c.req.query('error')) {\n throw new SocialAuthError('The provider did not send an authorization code.', 400, 'missing_code')\n }\n const result = await strategyFor(c, resolved).authenticate(c, {})\n if (result.type === 'error') throw result.error\n if (result.type !== 'success') {\n throw new SocialAuthError(\n result.type === 'fail' ? (result.message ?? 'Login failed.') : 'Login failed.',\n 401,\n )\n }\n const info = result.info as {\n profile: Profile\n tokens: OAuthTokens\n next?: string\n state?: { process?: Process }\n }\n const login = buildLogin(resolved, info.profile, {\n tokens: info.tokens,\n next: info.next,\n process: info.state?.process === 'connect' ? 'connect' : 'login',\n })\n return completeSocialLogin(c, login, 'browser')\n})\n\n/**\n * `POST <provider>/token/` `{ id_token }` or `{ access_token }`: log in with a token a native app got from the\n * provider's SDK. The token is checked against our client id(s) before it is trusted.\n */\nexport const nativeTokenView: ViewFunction = csrfExempt(\n guarded('api', async (c) => {\n if (c.req.method !== 'POST') return c.json({ detail: 'Method not allowed' }, 405)\n requireJson(c)\n const resolved = await provider(c)\n const body = (await c.req.json().catch(() => ({}))) as Record<string, unknown>\n const idToken = str(body.id_token)\n const accessToken = str(body.access_token)\n if (!idToken && !accessToken)\n throw new SocialAuthError('Send id_token or access_token.', 400, 'missing_token')\n let profile: Profile\n try {\n profile = await resolved.provider.verifyNativeToken(\n {\n key: resolved.key,\n app: resolved.app,\n settings: resolved.settings,\n callbackURL: '/',\n verify: async () => null,\n },\n { idToken, accessToken },\n )\n } catch (err) {\n throw new SocialAuthError((err as Error).message || 'Invalid token.', 401, 'invalid_token')\n }\n const login = buildLogin(resolved, profile, {\n tokens: accessToken ? { accessToken, raw: {} } : undefined,\n process: str(body.process) === 'connect' ? 'connect' : 'login',\n })\n return completeSocialLogin(c, login, 'api')\n }),\n)\n\n/** `POST token/` `{ code }`: exchange the one-time code from an SPA redirect for a JWT pair. */\nexport const tokenExchangeView: ViewFunction = csrfExempt(\n guarded('api', async (c) => {\n if (c.req.method !== 'POST') return c.json({ detail: 'Method not allowed' }, 405)\n requireJson(c)\n const body = (await c.req.json().catch(() => ({}))) as Record<string, unknown>\n const user = str(body.code) ? await redeemLoginCode(str(body.code)!) : null\n if (!user)\n throw new SocialAuthError('This login code is invalid, expired or already used.', 400, 'invalid_code')\n return c.json({ ...(await tokenPairForUser(user)), user: userInfo(user) })\n }),\n)\n\n/** `signup/`: finish a social signup that needs a username or email. */\nexport const signupView: ViewFunction = guarded(\n (c) => (wantsJson(c) ? 'api' : 'browser'),\n async (c) => {\n const pending = await readPendingSignup(c)\n if (!pending)\n throw new SocialAuthError('There is no social signup in progress.', 400, 'no_pending_signup')\n const resolved = await resolveProvider(pending.key)\n if (!resolved) throw new SocialAuthError('The provider is no longer configured.', 400, 'unknown_provider')\n const login = buildLogin(resolved, pending.profile, { tokens: pending.tokens, next: pending.next })\n const User = getUserModel()\n const uf = User.USERNAME_FIELD\n const ef = User.EMAIL_FIELD\n const json = wantsJson(c)\n const render = (values: Record<string, string>, errors: Record<string, string[]> = {}, status = 200) => {\n if (json) {\n return c.json(\n {\n provider: pending.key,\n profile: {\n email: pending.profile.email,\n username: pending.profile.username,\n name: pending.profile.name,\n },\n fields: [...new Set([uf, ef])],\n errors,\n },\n status as 200,\n )\n }\n const field = (name: string, label: string) =>\n `<label>${escapeHtml(label)}<input name=\"${escapeHtml(name)}\" value=\"${escapeHtml(values[name] ?? '')}\"></label>${(errors[name] ?? []).map((e) => `<p class=\"err\">${escapeHtml(e)}</p>`).join('')}`\n const fields = uf === ef ? field(ef, 'Email') : field(uf, 'Username') + field(ef, 'Email')\n return page(\n 'Finish signing up',\n `<p>You are signing up with ${escapeHtml(resolved.app.name ?? resolved.provider.name)}.</p><form method=\"post\">${csrfInput(c)}${fields}<button type=\"submit\">Sign up</button></form>`,\n status,\n )\n }\n if (c.req.method === 'GET') {\n return render({ [uf]: pending.profile.username ?? '', [ef]: pending.profile.email ?? '' })\n }\n const data = await readData(c)\n const values = { [uf]: String(data[uf] ?? ''), [ef]: String(data[ef] ?? '') }\n // An address the user typed is not verified by the provider.\n if (values[ef] && values[ef].toLowerCase() !== (pending.profile.email ?? '').toLowerCase())\n login.emailVerified = false\n const result = await signup(\n c,\n login,\n { username: values[uf], email: values[ef] },\n json ? 'api' : 'browser',\n )\n if (result instanceof Response) return expirePendingSignup(c, result)\n return render(values, result, 400)\n },\n)\n\n/** `connections/`: list the user's social accounts (GET) and disconnect one (POST `{ account }`). */\nexport const connectionsView: ViewFunction = guarded(\n (c) => (wantsJson(c) ? 'api' : 'browser'),\n async (c) => {\n const user = getUser(c)\n if (!user.isAuthenticated)\n throw new SocialAuthError('Log in to manage your connected accounts.', 401, 'login_required')\n const accounts = await SocialAccount.objects.filter({ user: user.pk } as any).orderBy('provider', 'id')\n if (c.req.method === 'POST') {\n const data = await readData(c)\n const id = String(data.account ?? '')\n const account = accounts.find((a) => String(a.pk) === id)\n if (!account) throw new SocialAuthError('No such connected account.', 404, 'not_found')\n const User = getUserModel()\n const full = await User.objects.filter({ pk: user.pk } as any).first()\n if (\n accounts.length === 1 &&\n full &&\n typeof (full as any).hasUsablePassword === 'function' &&\n !(full as any).hasUsablePassword()\n ) {\n throw new SocialAuthError(\n 'Set a password before disconnecting your last connected account.',\n 400,\n 'last_login_method',\n )\n }\n await account.delete()\n await socialAccountRemoved.send(SocialAccount, { c, account })\n if (wantsJson(c)) return c.json({ disconnected: id })\n return c.redirect(c.req.path, 302)\n }\n const list = accounts.map((a) => ({\n id: a.pk,\n provider: a.provider,\n uid: a.uid,\n lastLogin: a.lastLogin,\n dateJoined: a.dateJoined,\n }))\n if (wantsJson(c)) return c.json({ accounts: list })\n const rows = list\n .map(\n (a) =>\n `<li>${escapeHtml(a.provider)} <form method=\"post\" style=\"display:inline\">${csrfInput(c)}<input type=\"hidden\" name=\"account\" value=\"${escapeHtml(a.id)}\"><button type=\"submit\">Disconnect</button></form></li>`,\n )\n .join('')\n return page('Connected accounts', rows ? `<ul>${rows}</ul>` : '<p>No connected accounts.</p>')\n },\n)\n\n/**\n * `path('accounts/', include(socialUrls))` → `providers/`, `token/`, `signup/`, `connections/`,\n * `<provider>/login/`, `<provider>/login/callback/`, `<provider>/token/`.\n */\nexport const socialUrls = urlpatterns(undefined, [\n path('providers/', providersView, { name: 'socialaccount_providers' }),\n path('token/', tokenExchangeView, { name: 'socialaccount_token_exchange' }),\n path('signup/', signupView, { name: 'socialaccount_signup' }),\n path('connections/', connectionsView, { name: 'socialaccount_connections' }),\n path('<str:provider>/login/', loginView, { name: 'socialaccount_login' }),\n path('<str:provider>/login/callback/', callbackView, { name: 'socialaccount_callback' }),\n path('<str:provider>/token/', nativeTokenView, { name: 'socialaccount_native_token' }),\n])\n"],"mappings":"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","names":["getUserModel","cache","reverse","tryGetContext","seal","unseal","OAuth2Strategy","ImproperlyConfigured","provider","g","provider","OAuth2Strategy","tryGetContext","seal","unseal","cache","getUserModel","provider","getUserModel","reverse","getUserModel","tokenPairForUser","getUser","reverse","userInfo","reverse","getUser","tokenPairForUser","userInfo","getUserModel","values"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ghuri/socialauth",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.1",
|
|
4
4
|
"description": "Ghuri social login in django-allauth style: GitHub, Google, Facebook, Microsoft, Discord, GitLab and any OpenID Connect provider",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|