oneTap: async()

in packages/better-auth/src/plugins/one-tap/client.ts [87:187]


			oneTap: async (
				opts?: GoogleOneTapActionOptions,
				fetchOptions?: BetterFetchOption,
			) => {
				if (isRequestInProgress) {
					console.warn(
						"A Google One Tap request is already in progress. Please wait.",
					);
					return;
				}

				isRequestInProgress = true;

				try {
					if (typeof window === "undefined" || !window.document) {
						console.warn(
							"Google One Tap is only available in browser environments",
						);
						return;
					}

					const { autoSelect, cancelOnTapOutside, context } = opts ?? {};
					const contextValue = context ?? options.context ?? "signin";

					await loadGoogleScript();

					await new Promise<void>((resolve, reject) => {
						let isResolved = false;
						const baseDelay = options.promptOptions?.baseDelay ?? 1000;
						const maxAttempts = options.promptOptions?.maxAttempts ?? 5;

						window.google?.accounts.id.initialize({
							client_id: options.clientId,
							callback: async (response: { credential: string }) => {
								isResolved = true;
								try {
									await $fetch("/one-tap/callback", {
										method: "POST",
										body: { idToken: response.credential },
										...opts?.fetchOptions,
										...fetchOptions,
									});

									if (
										(!opts?.fetchOptions && !fetchOptions) ||
										opts?.callbackURL
									) {
										window.location.href = opts?.callbackURL ?? "/";
									}
									resolve();
								} catch (error) {
									console.error("Error during One Tap callback:", error);
									reject(error);
								}
							},
							auto_select: autoSelect,
							cancel_on_tap_outside: cancelOnTapOutside,
							context: contextValue,

							...options.additionalOptions,
						});

						const handlePrompt = (attempt: number) => {
							if (isResolved) return;

							window.google?.accounts.id.prompt((notification: any) => {
								if (isResolved) return;

								if (
									notification.isDismissedMoment &&
									notification.isDismissedMoment()
								) {
									if (attempt < maxAttempts) {
										const delay = Math.pow(2, attempt) * baseDelay;
										setTimeout(() => handlePrompt(attempt + 1), delay);
									} else {
										opts?.onPromptNotification?.(notification);
									}
								} else if (
									notification.isSkippedMoment &&
									notification.isSkippedMoment()
								) {
									if (attempt < maxAttempts) {
										const delay = Math.pow(2, attempt) * baseDelay;
										setTimeout(() => handlePrompt(attempt + 1), delay);
									} else {
										opts?.onPromptNotification?.(notification);
									}
								}
							});
						};

						handlePrompt(0);
					});
				} catch (error) {
					console.error("Error during Google One Tap flow:", error);
					throw error;
				} finally {
					isRequestInProgress = false;
				}
			},