import { n as E_UNAUTHORIZED_ACCESS } from "./errors-eDV8ejO0.js";
import { t as debug_default } from "./debug-CrTUB4zl.js";
import { RuntimeException } from "@adonisjs/core/exceptions";
import { HttpContextFactory } from "@adonisjs/core/factories/http";
//#region src/authenticator.ts
/**
* Authenticator is used to authenticate incoming HTTP requests
* using one or more known guards.
*/
var Authenticator = class {
	/**
	* Registered guards
	*/
	#config;
	/**
	* Cache of guards created during the HTTP request
	*/
	#guardsCache = {};
	/**
	* Last guard that was used to perform the authentication via
	* the "authenticateUsing" method.
	*
	* @note
	* Reset on every call made to "authenticate", "check" and
	* "authenticateUsing" method.
	*/
	#authenticationAttemptedViaGuard;
	/**
	* Name of the guard using which the request has
	* been authenticated successfully.
	*
	* @note
	* Reset on every call made to "authenticate", "check" and
	* "authenticateUsing" method.
	*/
	#authenticatedViaGuard;
	/**
	* Reference to HTTP context
	*/
	#ctx;
	/**
	* Name of the default guard configured in the auth configuration
	*
	* @example
	* const defaultGuard = auth.defaultGuard
	* console.log(defaultGuard) // 'web'
	*/
	get defaultGuard() {
		return this.#config.default;
	}
	/**
	* Reference to the guard using which the current
	* request has been authenticated. Returns undefined if
	* authentication has not been attempted or failed.
	*
	* @example
	* await auth.authenticate()
	* console.log(auth.authenticatedViaGuard) // 'web'
	*/
	get authenticatedViaGuard() {
		return this.#authenticatedViaGuard;
	}
	/**
	* A boolean to know if the current request has been authenticated. The
	* property returns false when "authenticate" or "authenticateUsing"
	* methods are not used.
	*
	* @example
	* await auth.authenticate()
	* console.log(auth.isAuthenticated) // true
	*/
	get isAuthenticated() {
		if (!this.#authenticationAttemptedViaGuard) return false;
		return this.use(this.#authenticationAttemptedViaGuard).isAuthenticated;
	}
	/**
	* Reference to the currently authenticated user. The property returns
	* undefined when "authenticate" or "authenticateUsing" methods are
	* not used.
	*
	* @example
	* await auth.authenticate()
	* console.log(auth.user?.email)
	*/
	get user() {
		if (!this.#authenticationAttemptedViaGuard) return;
		return this.use(this.#authenticationAttemptedViaGuard).user;
	}
	/**
	* Whether or not the authentication has been attempted during
	* the current request. The property returns false when the
	* "authenticate" or "authenticateUsing" methods are not
	* used.
	*
	* @example
	* await auth.check()
	* console.log(auth.authenticationAttempted) // true
	*/
	get authenticationAttempted() {
		if (!this.#authenticationAttemptedViaGuard) return false;
		return this.use(this.#authenticationAttemptedViaGuard).authenticationAttempted;
	}
	/**
	* Creates a new Authenticator instance
	*
	* @param ctx - The HTTP context for the current request
	* @param config - Configuration object containing default guard and available guards
	*
	* @example
	* const authenticator = new Authenticator(ctx, {
	*   default: 'web',
	*   guards: { web: sessionGuard }
	* })
	*/
	constructor(ctx, config) {
		this.#ctx = ctx;
		this.#config = config;
		debug_default("creating authenticator. config %O", this.#config);
	}
	/**
	* Returns an instance of the logged-in user or throws an exception
	*
	* @throws {RuntimeException} When authentication has not been attempted
	*
	* @example
	* const user = auth.getUserOrFail()
	* console.log(user.id)
	*/
	getUserOrFail() {
		if (!this.#authenticationAttemptedViaGuard) throw new RuntimeException("Cannot access authenticated user. Please call \"auth.authenticate\" method first.");
		return this.use(this.#authenticationAttemptedViaGuard).getUserOrFail();
	}
	/**
	* Returns an instance of a known guard. Guards instances are
	* cached during the lifecycle of an HTTP request.
	*
	* @param guard - Optional guard name. Uses default guard if not provided
	*
	* @example
	* const sessionGuard = auth.use('session')
	* const defaultGuard = auth.use()
	*/
	use(guard) {
		const guardToUse = guard || this.#config.default;
		/**
		* Use cached copy if exists
		*/
		const cachedGuard = this.#guardsCache[guardToUse];
		if (cachedGuard) {
			debug_default("authenticator: using guard from cache. name: \"%s\"", guardToUse);
			return cachedGuard;
		}
		const guardFactory = this.#config.guards[guardToUse];
		/**
		* Construct guard and cache it
		*/
		debug_default("authenticator: creating guard. name: \"%s\"", guardToUse);
		const guardInstance = guardFactory(this.#ctx);
		this.#guardsCache[guardToUse] = guardInstance;
		return guardInstance;
	}
	/**
	* Authenticate current request using the default guard. Calling this
	* method multiple times triggers multiple authentication with the
	* guard.
	*
	* @throws {E_UNAUTHORIZED_ACCESS} When authentication fails
	*
	* @example
	* const user = await auth.authenticate()
	* console.log('Authenticated user:', user.email)
	*/
	async authenticate() {
		await this.authenticateUsing();
		return this.getUserOrFail();
	}
	/**
	* Silently attempt to authenticate the request using the default
	* guard. Calling this method multiple times triggers multiple
	* authentication with the guard.
	*
	* @example
	* const isAuthenticated = await auth.check()
	* if (isAuthenticated) {
	*   console.log('User is authenticated')
	* }
	*/
	async check() {
		this.#authenticationAttemptedViaGuard = this.defaultGuard;
		const isAuthenticated = await this.use().check();
		if (isAuthenticated) this.#authenticatedViaGuard = this.defaultGuard;
		return isAuthenticated;
	}
	/**
	* Authenticate the request using all of the mentioned guards
	* or the default guard.
	*
	* The authentication process will stop after any of the mentioned
	* guards is able to authenticate the request successfully.
	*
	* Otherwise, "E_UNAUTHORIZED_ACCESS" will be raised.
	*
	* @param guards - Array of guard names to try for authentication
	* @param options - Options object with optional loginRoute for redirects
	*
	* @throws {E_UNAUTHORIZED_ACCESS} When none of the guards can authenticate
	*
	* @example
	* const user = await auth.authenticateUsing(['session', 'api'])
	* const userWithRedirect = await auth.authenticateUsing(['web'], { loginRoute: '/login' })
	*/
	async authenticateUsing(guards, options) {
		const guardsToUse = guards || [this.defaultGuard];
		let lastUsedDriver;
		for (let guardName of guardsToUse) {
			debug_default("attempting to authenticate using guard \"%s\"", guardName);
			this.#authenticationAttemptedViaGuard = guardName;
			const guard = this.use(guardName);
			lastUsedDriver = guard.driverName;
			if (await guard.check()) {
				this.#authenticatedViaGuard = guardName;
				return this.getUserOrFail();
			}
		}
		throw new E_UNAUTHORIZED_ACCESS("Unauthorized access", {
			guardDriverName: lastUsedDriver,
			redirectTo: options?.loginRoute
		});
	}
	/**
	* Silently attempt to authenticate the request using all of the mentioned guards
	* or the default guard. Calling this method multiple times triggers multiple
	* authentication with the guard.
	*
	* @param guards - Array of guard names to check. Defaults to default guard
	*
	* @example
	* const isAuthenticated = await auth.checkUsing(['session', 'api'])
	* if (isAuthenticated) {
	*   const user = auth.user
	* }
	*/
	async checkUsing(guards = [this.defaultGuard]) {
		for (const name of guards) {
			this.#authenticationAttemptedViaGuard = name;
			if (await this.use(name).check()) {
				this.#authenticatedViaGuard = name;
				return true;
			}
		}
		return false;
	}
};
//#endregion
//#region src/authenticator_client.ts
/**
* Authenticator client is used to create guard instances for testing.
* It passes a fake HTTPContext to the guards, so make sure to not
* call server side APIs that might be relying on a real
* HTTPContext instance.
*/
var AuthenticatorClient = class {
	/**
	* Registered guards
	*/
	#config;
	/**
	* Cache of guards
	*/
	#guardsCache = {};
	/**
	* Name of the default guard configured in the auth configuration
	*
	* @example
	* const client = new AuthenticatorClient({ default: 'web', guards: {} })
	* console.log(client.defaultGuard) // 'web'
	*/
	get defaultGuard() {
		return this.#config.default;
	}
	/**
	* Creates a new AuthenticatorClient instance for testing
	*
	* @param config - Configuration object containing default guard and available guards
	*
	* @example
	* const client = new AuthenticatorClient({
	*   default: 'web',
	*   guards: { web: sessionGuard }
	* })
	*/
	constructor(config) {
		this.#config = config;
		debug_default("creating authenticator client. config %O", this.#config);
	}
	/**
	* Returns an instance of a known guard. Guards instances are
	* cached during the lifecycle of an HTTP request.
	*
	* @param guard - Optional guard name. Uses default guard if not provided
	*
	* @example
	* const sessionGuard = client.use('session')
	* const defaultGuard = client.use()
	*/
	use(guard) {
		const guardToUse = guard || this.#config.default;
		/**
		* Use cached copy if exists
		*/
		const cachedGuard = this.#guardsCache[guardToUse];
		if (cachedGuard) {
			debug_default("authenticator client: using guard from cache. name: \"%s\"", guardToUse);
			return cachedGuard;
		}
		const guardFactory = this.#config.guards[guardToUse];
		/**
		* Construct guard and cache it
		*/
		debug_default("authenticator client: creating guard. name: \"%s\"", guardToUse);
		const guardInstance = guardFactory(new HttpContextFactory().create());
		this.#guardsCache[guardToUse] = guardInstance;
		return guardInstance;
	}
};
//#endregion
//#region src/auth_manager.ts
/**
* Auth manager exposes the API to register and manage authentication
* guards from the config
*/
var AuthManager = class {
	/**
	* Name of the default guard configured in the auth configuration
	*
	* @example
	* const manager = new AuthManager({ default: 'web', guards: {} })
	* console.log(manager.defaultGuard) // 'web'
	*/
	get defaultGuard() {
		return this.config.default;
	}
	/**
	* Creates a new AuthManager instance
	*
	* @param config - Configuration object containing default guard and available guards
	*
	* @example
	* const manager = new AuthManager({
	*   default: 'web',
	*   guards: { web: sessionGuard, api: tokenGuard }
	* })
	*/
	constructor(config) {
		this.config = config;
		this.config = config;
	}
	/**
	* Create an authenticator for a given HTTP request. The authenticator
	* is used to authenticate incoming HTTP requests
	*
	* @param ctx - The HTTP context for the current request
	*
	* @example
	* const authenticator = manager.createAuthenticator(ctx)
	* const user = await authenticator.authenticate()
	*/
	createAuthenticator(ctx) {
		return new Authenticator(ctx, this.config);
	}
	/**
	* Creates an instance of the authenticator client. The client is
	* used to setup authentication state during testing.
	*
	* @example
	* const client = manager.createAuthenticatorClient()
	* const guard = client.use('session')
	*/
	createAuthenticatorClient() {
		return new AuthenticatorClient(this.config);
	}
};
//#endregion
export { AuthenticatorClient as n, Authenticator as r, AuthManager as t };
