This commit is contained in:
seb
2026-07-19 16:37:45 +02:00
parent 17a36b2283
commit 9c20672e26
13 changed files with 481 additions and 26 deletions

View File

@@ -19,6 +19,31 @@ function loadGoogleScript() {
return scriptPromise;
}
export class GoogleSignInCancelledError extends Error {
constructor() {
super('Sign-in was cancelled');
this.name = 'GoogleSignInCancelledError';
}
}
export const FEDCM_BLOCKED_MESSAGE =
'Google sign-in is blocked for this site. Enable third-party sign-in using the icon next to the address bar, or in your browser site settings.';
export class GoogleSignInBlockedError extends Error {
constructor(message = FEDCM_BLOCKED_MESSAGE) {
super(message);
this.name = 'GoogleSignInBlockedError';
}
}
let activeAbort = null;
export function abortGoogleSignIn() {
if (!activeAbort) return;
window.google?.accounts?.id?.cancel();
activeAbort();
}
function clickRenderedGoogleButton(clientId, onCredential) {
const container = document.createElement('div');
container.style.cssText = 'position:fixed;left:-9999px;top:0;opacity:0;pointer-events:none;';
@@ -51,8 +76,10 @@ function clickRenderedGoogleButton(clientId, onCredential) {
/**
* Prompt for a Google ID token (One Tap, falling back to the sign-in popup).
* @param {string} clientId
* @param {{ onFedcmBlocked?: () => void }} [options]
*/
export async function requestGoogleIdToken(clientId) {
export async function requestGoogleIdToken(clientId, { onFedcmBlocked } = {}) {
if (!clientId) {
throw new Error('Google client ID is not configured');
}
@@ -65,9 +92,12 @@ export async function requestGoogleIdToken(clientId) {
const finish = (fn, value) => {
if (settled) return;
settled = true;
activeAbort = null;
fn(value);
};
activeAbort = () => finish(reject, new GoogleSignInCancelledError());
window.google.accounts.id.initialize({
client_id: clientId,
callback: (response) => finish(resolve, response.credential),
@@ -78,10 +108,21 @@ export async function requestGoogleIdToken(clientId) {
window.google.accounts.id.prompt((notification) => {
if (settled) return;
if (notification.isDismissedMoment()) {
if (notification.getDismissedReason() === 'credential_returned') return;
finish(reject, new GoogleSignInCancelledError());
return;
}
if (notification.isSkippedMoment()) {
const reason = notification.getSkippedReason?.();
if (reason === 'issuing_failed') {
onFedcmBlocked?.();
}
}
const needsFallback =
notification.isNotDisplayed() ||
notification.isSkippedMoment() ||
notification.isDismissedMoment();
notification.isNotDisplayed() || notification.isSkippedMoment();
if (!needsFallback) return;