@atlasauth/js 0.1.0

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.
Files changed (46) hide show
  1. package/dist/attempt.d.ts +71 -0
  2. package/dist/attempt.js +89 -0
  3. package/dist/attempt.js.map +1 -0
  4. package/dist/check-session.d.ts +56 -0
  5. package/dist/check-session.js +106 -0
  6. package/dist/check-session.js.map +1 -0
  7. package/dist/connect.d.ts +50 -0
  8. package/dist/connect.js +72 -0
  9. package/dist/connect.js.map +1 -0
  10. package/dist/fapi.d.ts +123 -0
  11. package/dist/fapi.js +314 -0
  12. package/dist/fapi.js.map +1 -0
  13. package/dist/index.d.ts +15 -0
  14. package/dist/index.js +43 -0
  15. package/dist/index.js.map +1 -0
  16. package/dist/native.d.ts +112 -0
  17. package/dist/native.js +201 -0
  18. package/dist/native.js.map +1 -0
  19. package/dist/passkey.d.ts +70 -0
  20. package/dist/passkey.js +126 -0
  21. package/dist/passkey.js.map +1 -0
  22. package/dist/password-reset.d.ts +41 -0
  23. package/dist/password-reset.js +80 -0
  24. package/dist/password-reset.js.map +1 -0
  25. package/dist/reauth.d.ts +29 -0
  26. package/dist/reauth.js +45 -0
  27. package/dist/reauth.js.map +1 -0
  28. package/dist/redirect.d.ts +38 -0
  29. package/dist/redirect.js +56 -0
  30. package/dist/redirect.js.map +1 -0
  31. package/dist/siwe.d.ts +23 -0
  32. package/dist/siwe.js +28 -0
  33. package/dist/siwe.js.map +1 -0
  34. package/dist/tab-election.d.ts +68 -0
  35. package/dist/tab-election.js +111 -0
  36. package/dist/tab-election.js.map +1 -0
  37. package/dist/telegram.d.ts +25 -0
  38. package/dist/telegram.js +18 -0
  39. package/dist/telegram.js.map +1 -0
  40. package/dist/telemetry.d.ts +125 -0
  41. package/dist/telemetry.js +357 -0
  42. package/dist/telemetry.js.map +1 -0
  43. package/dist/token-cache.d.ts +74 -0
  44. package/dist/token-cache.js +104 -0
  45. package/dist/token-cache.js.map +1 -0
  46. package/package.json +26 -0
package/dist/fapi.js ADDED
@@ -0,0 +1,314 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.initialFlow = exports.FapiClient = void 0;
4
+ exports.getProviderToken = getProviderToken;
5
+ exports.requestForStep = requestForStep;
6
+ exports.flowFromPending = flowFromPending;
7
+ exports.advance = advance;
8
+ exports.startSignUp = startSignUp;
9
+ exports.prepareFactor = prepareFactor;
10
+ exports.pollAttempt = pollAttempt;
11
+ exports.shouldKeepPolling = shouldKeepPolling;
12
+ const attempt_1 = require("./attempt");
13
+ class FapiClient {
14
+ options;
15
+ constructor(options) {
16
+ this.options = options;
17
+ }
18
+ async request(path, init = {}) {
19
+ const doFetch = this.options.fetchImpl ?? fetch;
20
+ let response;
21
+ try {
22
+ response = await doFetch(`${this.options.baseUrl ?? ''}${path}`, {
23
+ ...init,
24
+ // Cookies carry the session. A request without this is indistinguishable
25
+ // from being signed out, which is a maddening bug to chase.
26
+ credentials: 'include',
27
+ headers: {
28
+ 'x-publishable-key': this.options.publishableKey,
29
+ ...(init.body ? { 'content-type': 'application/json' } : {}),
30
+ ...init.headers,
31
+ },
32
+ });
33
+ }
34
+ catch {
35
+ /**
36
+ * A network failure is reported as a form-level error rather than thrown.
37
+ * A sign-in box that throws on a flaky connection unmounts itself and
38
+ * loses whatever the user had typed.
39
+ */
40
+ return {
41
+ ok: false,
42
+ status: 0,
43
+ data: null,
44
+ errors: [{ code: 'NETWORK', message: 'We could not reach the server.' }],
45
+ };
46
+ }
47
+ let body = null;
48
+ try {
49
+ body = await response.json();
50
+ }
51
+ catch {
52
+ // A 204, or an error page from a proxy. Neither should crash the parse.
53
+ }
54
+ return {
55
+ ok: response.ok,
56
+ status: response.status,
57
+ data: response.ok ? body : null,
58
+ // §9.1 messages are written for humans and surfaced verbatim.
59
+ errors: response.ok ? [] : (0, attempt_1.fieldErrors)(body),
60
+ };
61
+ }
62
+ post(path, body) {
63
+ return this.request(path, {
64
+ method: 'POST',
65
+ body: body === undefined ? undefined : JSON.stringify(body),
66
+ });
67
+ }
68
+ get(path) {
69
+ return this.request(path, { method: 'GET' });
70
+ }
71
+ }
72
+ exports.FapiClient = FapiClient;
73
+ /**
74
+ * Fetch the signed-in user's provider access token. Returns null when there is
75
+ * no usable token (no linked account, or the provider granted none / revoked
76
+ * it) — the caller's cue to prompt a re-connect rather than treat it as fatal.
77
+ * The server refreshes a stale token on read, single-flight, so the token
78
+ * handed back is always live.
79
+ */
80
+ async function getProviderToken(client, provider) {
81
+ const response = await client.get(`/v1/client/me/external_accounts/${encodeURIComponent(provider)}/token`);
82
+ if (!response.ok || !response.data)
83
+ return null;
84
+ return {
85
+ provider: response.data.provider,
86
+ accessToken: response.data.access_token,
87
+ expiresAt: response.data.expires_at ?? null,
88
+ scopes: response.data.scopes ?? [],
89
+ };
90
+ }
91
+ exports.initialFlow = {
92
+ attempt: null,
93
+ errors: [],
94
+ busy: false,
95
+ pollSecret: null,
96
+ ticket: null,
97
+ };
98
+ /**
99
+ * Which request the current step needs.
100
+ *
101
+ * Exported and tested separately from the network call, because this mapping is
102
+ * the part that can be wrong in a way nobody notices until a user is stuck.
103
+ */
104
+ function requestForStep(attempt, values) {
105
+ if (!attempt) {
106
+ return {
107
+ path: '/v1/client/sign_ins',
108
+ // §5 carry a captcha token when the sign-in flow gates the identifier
109
+ // step (an always-on per-flow captcha, or a risk-triggered challenge the
110
+ // server answered with needs_captcha).
111
+ body: {
112
+ identifier: values.identifier ?? '',
113
+ ...(values.captcha_token ? { captcha_token: values.captcha_token } : {}),
114
+ },
115
+ };
116
+ }
117
+ const step = (0, attempt_1.nextStep)(attempt);
118
+ const id = attempt.id ?? '';
119
+ switch (step.kind) {
120
+ case 'collect_identifier':
121
+ return {
122
+ path: '/v1/client/sign_ins',
123
+ body: {
124
+ identifier: values.identifier ?? '',
125
+ ...(values.captcha_token ? { captcha_token: values.captcha_token } : {}),
126
+ },
127
+ };
128
+ case 'collect_first_factor':
129
+ /**
130
+ * An emailed code and a password both arrive as "the thing the user
131
+ * typed", but they are different strategies on the same endpoint. The
132
+ * presence of a code field is what distinguishes them — a client-declared
133
+ * strategy would be a field the client can get wrong.
134
+ */
135
+ return values.code
136
+ ? {
137
+ path: `/v1/client/sign_ins/${id}/attempt_first_factor`,
138
+ body: { strategy: 'email_code', code: values.code },
139
+ }
140
+ : {
141
+ path: `/v1/client/sign_ins/${id}/attempt_first_factor`,
142
+ body: { strategy: 'password', password: values.password ?? '' },
143
+ };
144
+ case 'collect_second_factor':
145
+ // Only ever the code (+ the §5.3 "remember this device" opt-in). Sending
146
+ // `password` here would be posting a credential to an endpoint that has no
147
+ // business seeing one.
148
+ return {
149
+ path: `/v1/client/sign_ins/${id}/attempt_second_factor`,
150
+ body: {
151
+ code: values.code ?? '',
152
+ ...(values.remember_device === 'true' ? { remember_device: true } : {}),
153
+ },
154
+ };
155
+ /**
156
+ * §11.1 MFA policy `required`. Two consecutive codes, and the factor id
157
+ * from the prepare step — a different endpoint from the second factor,
158
+ * because there is no factor to verify against yet.
159
+ */
160
+ case 'enroll_second_factor':
161
+ return {
162
+ path: `/v1/client/sign_ins/${id}/attempt_mfa_enrollment`,
163
+ body: {
164
+ factor_id: values.factorId ?? '',
165
+ codes: [values.code ?? '', values.secondCode ?? ''],
166
+ },
167
+ };
168
+ case 'collect_email_code':
169
+ return {
170
+ path: `/v1/client/sign_ups/${id}/attempt_verification`,
171
+ body: { code: values.code ?? '' },
172
+ };
173
+ case 'collect_captcha':
174
+ /**
175
+ * §5 the challenge marker carries no attempt id — the server withheld the
176
+ * attempt until the captcha clears. There is nothing to submit until the
177
+ * widget yields a token (the client should render the captcha, not POST);
178
+ * once solved, re-issue the identifier POST WITH the token to create the
179
+ * real attempt. Submitting without a token just re-triggers the challenge.
180
+ */
181
+ return values.captcha_token
182
+ ? {
183
+ path: '/v1/client/sign_ins',
184
+ body: {
185
+ identifier: values.identifier ?? '',
186
+ captcha_token: values.captcha_token,
187
+ },
188
+ }
189
+ : null;
190
+ case 'collect_new_password':
191
+ return {
192
+ path: `/v1/client/password_resets/${id}/set_new_password`,
193
+ body: { password: values.password ?? '' },
194
+ };
195
+ case 'await_oauth':
196
+ case 'done':
197
+ case 'restart':
198
+ case 'unknown':
199
+ /**
200
+ * Nothing to submit. Returning null rather than a best guess means a
201
+ * component cannot accidentally POST to an endpoint that does not apply
202
+ * to the state the server put it in.
203
+ */
204
+ return null;
205
+ }
206
+ }
207
+ /**
208
+ * §5.3: seed a flow from an attempt the app was handed mid-stream — an OAuth
209
+ * redirect that came back needing a second factor (`__atlas_status`), with no
210
+ * ticket because the server withheld the session until the factor is passed.
211
+ *
212
+ * The attempt id lets the next submit target the right attempt; the status
213
+ * routes the UI to the step the server is demanding. A null pending attempt —
214
+ * the ordinary fresh sign-in — yields the empty initial flow.
215
+ */
216
+ function flowFromPending(pending) {
217
+ if (!pending)
218
+ return exports.initialFlow;
219
+ return {
220
+ ...exports.initialFlow,
221
+ attempt: { id: pending.id, status: pending.status },
222
+ };
223
+ }
224
+ /** Advance the flow by one step. Never decides the next status itself. */
225
+ async function advance(client, state, values) {
226
+ const request = requestForStep(state.attempt, values);
227
+ if (!request)
228
+ return state;
229
+ const response = await client.post(request.path, request.body);
230
+ if (!response.ok || !response.data) {
231
+ /**
232
+ * The attempt is KEPT on failure. Clearing it would drop the user back to
233
+ * the identifier step after one wrong password, losing the progress they
234
+ * made and re-triggering the anti-enumeration path for no reason.
235
+ */
236
+ return { ...state, busy: false, errors: response.errors };
237
+ }
238
+ return {
239
+ attempt: response.data,
240
+ errors: [],
241
+ busy: false,
242
+ pollSecret: state.pollSecret,
243
+ // A completion response carries the ticket to exchange for cookies.
244
+ ticket: response.data.ticket ?? null,
245
+ };
246
+ }
247
+ /**
248
+ * §5 Begin a password sign-up. POSTs email + password + the tenant's configured
249
+ * extra fields (name, company, phone, custom…) to `/v1/client/sign_ups` and
250
+ * returns a flow. Usually `needs_email_verification` — the shared `advance` then
251
+ * drives the emailed code to completion — or, when the instance doesn't gate on
252
+ * verification, a `complete` attempt carrying the session ticket.
253
+ */
254
+ async function startSignUp(client, input) {
255
+ const hasFields = input.fields && Object.keys(input.fields).length > 0;
256
+ const response = await client.post('/v1/client/sign_ups', {
257
+ email: input.email,
258
+ password: input.password,
259
+ ...(hasFields ? { fields: input.fields } : {}),
260
+ // §5.1 forward the legal-consent tick so the server can enforce a REQUIRED
261
+ // agreement (the disabled submit is only a client-side courtesy).
262
+ ...(input.consent ? { consent: true } : {}),
263
+ // §5 the bot-defence token, when the sign-up flow's captcha is enabled.
264
+ ...(input.captchaToken ? { captcha_token: input.captchaToken } : {}),
265
+ });
266
+ if (!response.ok || !response.data) {
267
+ return { ...exports.initialFlow, busy: false, errors: response.errors };
268
+ }
269
+ return {
270
+ attempt: response.data,
271
+ errors: [],
272
+ busy: false,
273
+ pollSecret: exports.initialFlow.pollSecret,
274
+ ticket: response.data.ticket ?? null,
275
+ };
276
+ }
277
+ /** §5.3: ask the server to send a code or a magic link. */
278
+ async function prepareFactor(client, state, strategy) {
279
+ const id = state.attempt?.id;
280
+ if (!id)
281
+ return state;
282
+ const response = await client.post(`/v1/client/sign_ins/${id}/prepare_first_factor`, { strategy });
283
+ if (!response.ok)
284
+ return { ...state, busy: false, errors: response.errors };
285
+ return {
286
+ ...state,
287
+ busy: false,
288
+ errors: [],
289
+ // Held in memory only. It is what lets THIS tab collect a sign-in completed
290
+ // by a link opened on another device.
291
+ pollSecret: response.data?.poll_secret ?? null,
292
+ };
293
+ }
294
+ /**
295
+ * §5.3 polling. Returns the updated flow, and a ticket once the link has been
296
+ * opened somewhere.
297
+ */
298
+ async function pollAttempt(client, state) {
299
+ const id = state.attempt?.id;
300
+ if (!id || !state.pollSecret)
301
+ return { state, ticket: null };
302
+ const response = await client.get(`/v1/client/sign_ins/${id}?poll_secret=${encodeURIComponent(state.pollSecret)}`);
303
+ if (!response.ok || !response.data)
304
+ return { state, ticket: null };
305
+ return {
306
+ state: { ...state, attempt: response.data },
307
+ ticket: response.data.ticket ?? null,
308
+ };
309
+ }
310
+ /** Whether polling should continue, so a tab does not poll a dead attempt forever. */
311
+ function shouldKeepPolling(state) {
312
+ return Boolean(state.pollSecret) && Boolean(state.attempt) && !(0, attempt_1.isTerminal)(state.attempt);
313
+ }
314
+ //# sourceMappingURL=fapi.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fapi.js","sourceRoot":"","sources":["../src/fapi.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ export * from './token-cache';
2
+ export * from './tab-election';
3
+ export * from './attempt';
4
+ export * from './redirect';
5
+ export * from './fapi';
6
+ export * from './native';
7
+ export * from './passkey';
8
+ export * from './telegram';
9
+ export * from './siwe';
10
+ export * from './telemetry';
11
+ export * from './reauth';
12
+ export * from './connect';
13
+ export * from './password-reset';
14
+ export * from './check-session';
15
+ export { type AuthzClaims, type ProtectCondition, type ProtectOutcome, type ProtectReason, evaluate, hasFromClaims, protectFromClaims, ForbiddenError, ROLE_KEY_PATTERN, PERMISSION_KEY_PATTERN, isRoleKey, isPermissionKey, } from '@atlasauth/authz';
package/dist/index.js ADDED
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.isPermissionKey = exports.isRoleKey = exports.PERMISSION_KEY_PATTERN = exports.ROLE_KEY_PATTERN = exports.ForbiddenError = exports.protectFromClaims = exports.hasFromClaims = exports.evaluate = void 0;
18
+ __exportStar(require("./token-cache"), exports);
19
+ __exportStar(require("./tab-election"), exports);
20
+ __exportStar(require("./attempt"), exports);
21
+ __exportStar(require("./redirect"), exports);
22
+ __exportStar(require("./fapi"), exports);
23
+ __exportStar(require("./native"), exports);
24
+ __exportStar(require("./passkey"), exports);
25
+ __exportStar(require("./telegram"), exports);
26
+ __exportStar(require("./siwe"), exports);
27
+ __exportStar(require("./telemetry"), exports);
28
+ __exportStar(require("./reauth"), exports);
29
+ __exportStar(require("./connect"), exports);
30
+ __exportStar(require("./password-reset"), exports);
31
+ __exportStar(require("./check-session"), exports);
32
+ // Framework-agnostic authorization primitive — `has()`/`evaluate` for any
33
+ // non-React/Next consumer reading org_role/org_permissions off its session.
34
+ var authz_1 = require("@atlasauth/authz");
35
+ Object.defineProperty(exports, "evaluate", { enumerable: true, get: function () { return authz_1.evaluate; } });
36
+ Object.defineProperty(exports, "hasFromClaims", { enumerable: true, get: function () { return authz_1.hasFromClaims; } });
37
+ Object.defineProperty(exports, "protectFromClaims", { enumerable: true, get: function () { return authz_1.protectFromClaims; } });
38
+ Object.defineProperty(exports, "ForbiddenError", { enumerable: true, get: function () { return authz_1.ForbiddenError; } });
39
+ Object.defineProperty(exports, "ROLE_KEY_PATTERN", { enumerable: true, get: function () { return authz_1.ROLE_KEY_PATTERN; } });
40
+ Object.defineProperty(exports, "PERMISSION_KEY_PATTERN", { enumerable: true, get: function () { return authz_1.PERMISSION_KEY_PATTERN; } });
41
+ Object.defineProperty(exports, "isRoleKey", { enumerable: true, get: function () { return authz_1.isRoleKey; } });
42
+ Object.defineProperty(exports, "isPermissionKey", { enumerable: true, get: function () { return authz_1.isPermissionKey; } });
43
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,gDAA8B;AAC9B,iDAA+B;AAC/B,4CAA0B;AAC1B,6CAA2B;AAC3B,yCAAuB;AACvB,2CAAyB;AACzB,4CAA0B;AAC1B,6CAA2B;AAC3B,yCAAuB;AACvB,8CAA4B;AAC5B,2CAAyB;AACzB,4CAA0B;AAC1B,mDAAiC;AACjC,kDAAgC;AAChC,0EAA0E;AAC1E,4EAA4E;AAC5E,0CAa0B;AARxB,iGAAA,QAAQ,OAAA;AACR,sGAAA,aAAa,OAAA;AACb,0GAAA,iBAAiB,OAAA;AACjB,uGAAA,cAAc,OAAA;AACd,yGAAA,gBAAgB,OAAA;AAChB,+GAAA,sBAAsB,OAAA;AACtB,kGAAA,SAAS,OAAA;AACT,wGAAA,eAAe,OAAA"}
@@ -0,0 +1,112 @@
1
+ /**
2
+ * §6 native / One-Tap sign-in — the client half.
3
+ *
4
+ * The SDK does not make HTTP calls (the app owns fetch + cookies), so this
5
+ * module is two pure helpers for the request/response shape plus a
6
+ * framework-agnostic Google Identity Services loader that resolves a credential
7
+ * id_token. The app posts that to `/v1/client/sign_ins/id_token` and then reads
8
+ * the result exactly like any other attempt (nextStep / a returned ticket).
9
+ */
10
+ export interface NativeSignInBody {
11
+ provider: string;
12
+ id_token: string;
13
+ nonce?: string;
14
+ }
15
+ /** Build the POST body for `/v1/client/sign_ins/id_token`. */
16
+ export declare function nativeSignInBody(input: {
17
+ provider: string;
18
+ idToken: string;
19
+ nonce?: string;
20
+ }): NativeSignInBody;
21
+ export interface NativeSignInResult {
22
+ attemptId: string;
23
+ status: string;
24
+ /** Present only when the sign-in completed — exchange it for cookies. */
25
+ ticket?: string;
26
+ }
27
+ /**
28
+ * Parse the native sign-in response. A `ticket` means complete; a status
29
+ * without a ticket (e.g. `needs_second_factor`) means a factor is still owed —
30
+ * the same contract the redirect flow uses, so callers must not treat it as
31
+ * signed-in.
32
+ */
33
+ export declare function parseNativeSignInResponse(body: unknown): NativeSignInResult | null;
34
+ interface GsiId {
35
+ initialize(config: Record<string, unknown>): void;
36
+ prompt(listener?: (notification: unknown) => void): void;
37
+ renderButton(parent: HTMLElement, options: Record<string, unknown>): void;
38
+ cancel(): void;
39
+ }
40
+ interface GsiHost {
41
+ google?: {
42
+ accounts?: {
43
+ id?: GsiId;
44
+ };
45
+ };
46
+ document: Document;
47
+ ResizeObserver?: typeof ResizeObserver;
48
+ }
49
+ /** Inject the GSI script once; resolves when it is ready. */
50
+ export declare function loadGoogleIdentityServices(doc: Document): Promise<void>;
51
+ /** Reset the one-shot loader (tests). */
52
+ export declare function resetGoogleIdentityServices(): void;
53
+ /**
54
+ * Load GSI and resolve a Google credential (an OIDC id_token) from One-Tap.
55
+ * The nonce, when supplied, is embedded in the credential and MUST be echoed to
56
+ * the server so it can bind the token to this request.
57
+ */
58
+ export declare function requestGoogleCredential(opts: {
59
+ clientId: string;
60
+ nonce?: string;
61
+ autoSelect?: boolean;
62
+ host?: GsiHost;
63
+ }): Promise<string>;
64
+ /**
65
+ * Render the official "Sign in with Google" BUTTON into `parent` (and, when
66
+ * `oneTap` is set, also show the One-Tap prompt). Each resolved credential
67
+ * id_token is handed to `onCredential`, which the app posts to
68
+ * /v1/client/sign_ins/id_token. Unlike {@link requestGoogleCredential} this does
69
+ * not resolve once — a button can be clicked repeatedly — so it takes a
70
+ * callback. Framework-agnostic: the caller owns the DOM node and the fetch.
71
+ */
72
+ export declare function renderGoogleButton(opts: {
73
+ parent: HTMLElement;
74
+ clientId: string;
75
+ nonce?: string;
76
+ onCredential: (idToken: string) => void;
77
+ onError?: (error: Error) => void;
78
+ /** GSI renderButton options (theme, size, text, shape, width…). */
79
+ buttonOptions?: Record<string, unknown>;
80
+ /** Also show the One-Tap prompt above the button. */
81
+ oneTap?: boolean;
82
+ host?: GsiHost;
83
+ }): Promise<void>;
84
+ /**
85
+ * Render YOUR uniform button, backed by Google's real (but invisible) GSI button.
86
+ *
87
+ * Google refuses to let you style its button, and One-Tap is FedCM-flaky — so to
88
+ * show your OWN button while still using the secretless id_token flow, you overlay
89
+ * Google's real button, at opacity 0, exactly on top of your styled one. The user
90
+ * sees your button; the click lands on Google's, which mints the id_token. No
91
+ * secret, no redirect.
92
+ *
93
+ * The failure mode people hit is misalignment — the invisible button not covering
94
+ * the visible one, so clicks miss. This guards against it: the overlay fills the
95
+ * wrapper, and a ResizeObserver keeps Google's button width matched to yours so
96
+ * the whole surface stays clickable as the layout changes.
97
+ *
98
+ * `wrapper` is YOUR styled button (or its container); it is made position:relative
99
+ * if it is not already positioned. Returns `{ destroy }` to tear the overlay down.
100
+ */
101
+ export declare function renderGoogleOverlayButton(opts: {
102
+ wrapper: HTMLElement;
103
+ clientId: string;
104
+ nonce?: string;
105
+ onCredential: (idToken: string) => void;
106
+ onError?: (error: Error) => void;
107
+ size?: 'large' | 'medium' | 'small';
108
+ host?: GsiHost;
109
+ }): Promise<{
110
+ destroy: () => void;
111
+ }>;
112
+ export {};