ensureHook(name) {
		if (typeof name !== "string") {
			return name;
		}
		name = toCamelCase(name);
		if (name.startsWith("before")) {
			return /** @type {ResolveStepHook} */ (
				this.ensureHook(name[6].toLowerCase() + name.slice(7)).withOptions({
					stage: -10,
				})
			);
		}
		if (name.startsWith("after")) {
			return /** @type {ResolveStepHook} */ (
				this.ensureHook(name[5].toLowerCase() + name.slice(6)).withOptions({
					stage: 10,
				})
			);
		}
		/** @type {ResolveStepHook} */
		const hook = /** @type {KnownHooks & EnsuredHooks} */ (this.hooks)[name];
		if (!hook) {
			/** @type {KnownHooks & EnsuredHooks} */
			(this.hooks)[name] = new AsyncSeriesBailHook(
				["request", "resolveContext"],
				name,
			);

			return /** @type {KnownHooks & EnsuredHooks} */ (this.hooks)[name];
		}
		return hook;
	}
@param {string | ResolveStepHook} name hook name or hook itself
@returns {ResolveStepHook} the hook