@baliola/auth-sdk 0.5.0 → 0.6.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.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,44 @@
2
2
 
3
3
  All notable changes to `@baliola/auth-sdk` are documented here.
4
4
 
5
+ ## 0.6.0
6
+
7
+ Hosted Google login. baliola-auth now runs the Google OAuth round trip itself
8
+ (`GET /auth/google/start`, `GET /auth/google/callback`, `POST /auth/google/exchange`),
9
+ so an app can offer "Sign in with Google" without loading Google Identity Services. The
10
+ browser only ever sees a one-time code, never a token.
11
+
12
+ - feat(client): `auth.google.signInWithPopup(opts?)` opens the hosted login in a popup,
13
+ waits for the exit message, exchanges the one-time code, and stores the session.
14
+ `opts.returnTo` (default: current href without hash) and `opts.popup.width` /
15
+ `opts.popup.height` (default 500 x 640). Browser only.
16
+ - feat(client): `auth.google.completeRedirect(opts?)` finishes a hosted login started in
17
+ `redirect` mode on the `returnTo` page: resolves `null` when the URL carries no `code`
18
+ or `error`, verifies the nonce saved by `startUrl`, strips `code`, `error`, and `nonce`
19
+ from the URL before exchanging. Browser only.
20
+ - feat(client): `auth.google.startUrl({ mode, returnTo?, nonce })` builds the
21
+ `/auth/google/start` URL from the client's `clientId`, and `auth.google.exchange({ code })`
22
+ posts the one-time code and stores the session like every other login method. Both are
23
+ the manual path underneath the two methods above.
24
+ - feat(errors): `GoogleSignInCancelledError` (`code: 'oauth_cancelled'`,
25
+ `reason: 'popup_blocked' | 'popup_closed' | 'access_denied'`) and `GoogleSignInError`
26
+ (`code` is the exit or exchange failure: `invalid_google_code`, `email_unverified`,
27
+ `invalid_oauth_state`, `oauth_unexpected`, or the SDK-side `oauth_nonce_mismatch`).
28
+ `authErrorFromResponse` now maps server `invalid_google_code` and `email_unverified` to
29
+ `GoogleSignInError`; `status` and `code` are unchanged, so `instanceof AuthError` and
30
+ `err.code` branches keep working.
31
+ - feat(types): `GoogleExchangeInput`, `GoogleStartMode`, `GoogleStartOptions`,
32
+ `GoogleSignInWithPopupOptions`, `GoogleCompleteRedirectOptions`, and
33
+ `GoogleSignInCancelledReason` are exported from the root and the `./types` (or
34
+ `./errors`) subpath.
35
+ - feat(client)!: **Breaking.** `auth.google.login` accepts `{ idToken }` only.
36
+ `LoginWithGoogleInput` is narrowed from `{ idToken: string } | { code: string }` to
37
+ `{ idToken: string }`. The server no longer accepts `{ code }` on `/auth/google/login`
38
+ (it is a 400 now); apps that used the Google Identity Services code client should move
39
+ to `auth.google.signInWithPopup()`. `RELEASING.md` would call this removal a major
40
+ bump; the user chose 0.6.0 under the pre-1.0 rule that breaks ship as minors with an
41
+ explicit CHANGELOG callout, which this bullet is.
42
+
5
43
  ## 0.5.0
6
44
 
7
45
  - feat(types): `auth.getProfile()` now returns `account.hasPassword`, a boolean
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @baliola/auth-sdk
2
2
 
3
- Client SDK for the Baliola Auth service. Two clearly separated email flows (passwordless OTP, password + verification OTP) plus Google login, with typed methods, typed errors, auto-refresh, and cross-tab sync.
3
+ Client SDK for the Baliola Auth service. Two clearly separated email flows (passwordless OTP, password + verification OTP) plus Google login (hosted popup, hosted redirect, or Google Identity Services), with typed methods, typed errors, auto-refresh, and cross-tab sync.
4
4
 
5
5
  Guides:
6
6
 
@@ -98,15 +98,44 @@ auth.emailPassword.changePassword({ currentPassword, newPassword });
98
98
 
99
99
  ### `auth.google`
100
100
 
101
+ Three ways in. The hosted flow needs a `clientId` on the client and a `returnTo` whose origin is
102
+ one of the project's `allowedOrigins`. Google Identity Services is not loaded in your page.
103
+
101
104
  ```ts
102
- // idToken comes from the Google Identity Services button or One Tap.
103
- auth.google.login({ idToken }); // → AuthSession
105
+ import { GoogleSignInCancelledError, GoogleSignInError } from '@baliola/auth-sdk';
106
+
107
+ // 1. Hosted popup (recommended). Opens the auth server's Google login in a popup,
108
+ // exchanges the one-time code it posts back, and stores the session.
109
+ try {
110
+ const session = await auth.google.signInWithPopup();
111
+ // optional: { returnTo: '/auth/callback', popup: { width: 500, height: 640 } }
112
+ } catch (e) {
113
+ if (e instanceof GoogleSignInCancelledError) return; // e.reason: 'popup_blocked' | 'popup_closed' | 'access_denied'
114
+ if (e instanceof GoogleSignInError) return showError(e.code); // 'email_unverified', 'invalid_google_code', ...
115
+ throw e;
116
+ }
117
+
118
+ // 2. Hosted redirect. Send the tab to Google, then finish on the returnTo page.
119
+ location.assign(auth.google.startUrl({ mode: 'redirect', nonce: crypto.randomUUID() }));
120
+ // ...on the returnTo page, at boot:
121
+ const session = await auth.google.completeRedirect(); // null when the URL has no code or error
104
122
 
105
- // code comes from the OAuth popup code flow (google.accounts.oauth2.initCodeClient).
106
- // The server exchanges it for the ID token with its client secret.
107
- auth.google.login({ code }); // → AuthSession
123
+ // 3. Google Identity Services. idToken comes from the GIS button or One Tap.
124
+ auth.google.login({ idToken }); // AuthSession
108
125
  ```
109
126
 
127
+ Manual control: `startUrl({ mode: 'popup' | 'redirect', returnTo?, nonce })` builds
128
+ `GET {baseUrl}/auth/google/start`, and `exchange({ code })` turns the one-time code from the exit into
129
+ a stored session. Both are what `signInWithPopup` and `completeRedirect` use internally.
130
+
131
+ How the popup exit reaches you: the auth server's callback page runs
132
+ `window.opener.postMessage({ type: 'baliola-auth:google', nonce, code }, returnToOrigin)` on success,
133
+ or `{ type: 'baliola-auth:google', nonce, error }` on failure, then closes. `signInWithPopup` accepts
134
+ a message only when `event.origin` is the auth server origin, `type` matches, and `nonce` is the one
135
+ it generated. In `redirect` mode the exit is a 302 to `returnTo` with `code` and `nonce` (or `error`
136
+ and `nonce`) query params; `completeRedirect` checks `nonce` against the value `startUrl` saved in
137
+ `sessionStorage` and strips all three params from the URL before exchanging.
138
+
110
139
  ### Custodial wallet (smart-account signer)
111
140
 
112
141
  ```ts
@@ -196,6 +225,8 @@ import {
196
225
  RateLimitedError,
197
226
  InvalidPasswordError,
198
227
  InvalidEmailError,
228
+ GoogleSignInCancelledError,
229
+ GoogleSignInError,
199
230
  } from '@baliola/auth-sdk';
200
231
 
201
232
  try {
@@ -213,19 +244,21 @@ try {
213
244
  | Error class | `code` | Status | Carries |
214
245
  | ------------------------------ | ---------------------------- | ------ | ------------------------------------------ |
215
246
  | `OtpInvalidError` | `otp_invalid` | 400 | `attemptsRemaining`, `canResendInSeconds` |
216
- | `OtpExpiredError` | `otp_expired` | 400 | |
247
+ | `OtpExpiredError` | `otp_expired` | 400 | none |
217
248
  | `MaxAttemptsError` | `max_attempts_exceeded` | 429 | `retryAfterSeconds` |
218
- | `NoPendingOtpError` | `no_pending_otp` | 400 | |
249
+ | `NoPendingOtpError` | `no_pending_otp` | 400 | none |
219
250
  | `ResendCooldownError` | `resend_cooldown` | 429 | `canResendInSeconds` |
220
- | `MaxResendsError` | `max_resends_exceeded` | 429 | |
221
- | `InvalidCredentialsError` | `invalid_credentials` | 401 | |
222
- | `NoPasswordSetError` | `no_password_set` | 400 | |
223
- | `AccountSuspendedError` | `account_suspended` | 403 | |
224
- | `EmailAlreadyHasPasswordError` | `email_already_has_password` | 409 | |
225
- | `CaptchaFailedError` | `captcha_failed` | 400 | |
251
+ | `MaxResendsError` | `max_resends_exceeded` | 429 | none |
252
+ | `InvalidCredentialsError` | `invalid_credentials` | 401 | none |
253
+ | `NoPasswordSetError` | `no_password_set` | 400 | none |
254
+ | `AccountSuspendedError` | `account_suspended` | 403 | none |
255
+ | `EmailAlreadyHasPasswordError` | `email_already_has_password` | 409 | none |
256
+ | `CaptchaFailedError` | `captcha_failed` | 400 | none |
226
257
  | `InvalidPasswordError` | `invalid_password` | 400 | `reason: 'too_short'\|'no_uppercase'\|...` |
227
- | `InvalidEmailError` | `invalid_email` | 400 | |
258
+ | `InvalidEmailError` | `invalid_email` | 400 | none |
228
259
  | `RateLimitedError` | (legacy 429) | 429 | `retryAfterSeconds`, `retryAfterHuman` |
260
+ | `GoogleSignInCancelledError` | `oauth_cancelled` | 0 | `reason: 'popup_blocked'\|'popup_closed'\|'access_denied'` |
261
+ | `GoogleSignInError` | `invalid_google_code`, `email_unverified`, `invalid_oauth_state`, `oauth_unexpected`, `oauth_nonce_mismatch` | 401 / 400 / 0 | none |
229
262
  | `AuthError` (base) | varies | varies | `status: 0` for network/timeout |
230
263
 
231
264
  ## Stores
@@ -309,7 +342,7 @@ if (session) {
309
342
  }
310
343
  ```
311
344
 
312
- **`auth.emailOtp.verifyLoginCode` / `auth.emailPassword.verifyRegistrationCode` / `auth.emailPassword.login` / `auth.google.login` success (`AuthSession`):**
345
+ **`auth.emailOtp.verifyLoginCode` / `auth.emailPassword.verifyRegistrationCode` / `auth.emailPassword.login` / `auth.google.login` / `auth.google.exchange` success (`AuthSession`):**
313
346
 
314
347
  ```json
315
348
  {
@@ -349,6 +382,19 @@ if (session) {
349
382
  }
350
383
  ```
351
384
 
385
+ **`auth.google.exchange` failure (`GoogleSignInError`, 401):**
386
+
387
+ ```json
388
+ {
389
+ "message": "Invalid or expired login code",
390
+ "data": null,
391
+ "error": {
392
+ "code": "invalid_google_code",
393
+ "details": { "name": "UnauthorizedError", "requestId": "..." }
394
+ }
395
+ }
396
+ ```
397
+
352
398
  ## License
353
399
 
354
400
  Proprietary — see [LICENSE](./LICENSE).
@@ -92,6 +92,32 @@ declare class InvalidPasswordError extends AuthError {
92
92
  declare class InvalidEmailError extends AuthError {
93
93
  constructor(init: AuthErrorInit);
94
94
  }
95
+ type GoogleSignInCancelledReason = 'popup_blocked' | 'popup_closed' | 'access_denied';
96
+ /**
97
+ * The hosted Google sign-in ended without a session because of the user or
98
+ * the browser: the popup was blocked, the popup was closed early, or the
99
+ * user cancelled on Google's account chooser. `code` is always
100
+ * `oauth_cancelled`; branch on `reason` for the specific cause.
101
+ */
102
+ declare class GoogleSignInCancelledError extends AuthError {
103
+ readonly reason: GoogleSignInCancelledReason;
104
+ constructor(init: {
105
+ reason: GoogleSignInCancelledReason;
106
+ cause?: unknown;
107
+ });
108
+ }
109
+ /**
110
+ * The hosted Google sign-in failed. `code` is the failure code the exit or
111
+ * the exchange returned: `invalid_oauth_state`, `invalid_google_code`,
112
+ * `email_unverified`, `oauth_unexpected`, or the SDK-side
113
+ * `oauth_nonce_mismatch`. `status` is the HTTP status when the exchange
114
+ * request failed, otherwise `0`.
115
+ */
116
+ declare class GoogleSignInError extends AuthError {
117
+ constructor(init: {
118
+ code: string;
119
+ } & Partial<AuthErrorInit>);
120
+ }
95
121
  /**
96
122
  * Map a backend error response onto the right AuthError subclass.
97
123
  * Falls back to `AuthError` (with status + code preserved) for unknown codes.
@@ -100,4 +126,4 @@ declare function authErrorFromResponse(response: Response): Promise<AuthError>;
100
126
  /** Network/timeout failures land here. */
101
127
  declare function authErrorFromFetchFailure(cause: unknown, isTimeout?: boolean): AuthError;
102
128
  //#endregion
103
- export { authErrorFromFetchFailure as _, EmailAlreadyHasPasswordError as a, InvalidPasswordError as c, NoPasswordSetError as d, NoPendingOtpError as f, ResendCooldownError as g, RateLimitedError as h, CaptchaFailedError as i, MaxAttemptsError as l, OtpInvalidError as m, AuthError as n, InvalidCredentialsError as o, OtpExpiredError as p, AuthErrorInit as r, InvalidEmailError as s, AccountSuspendedError as t, MaxResendsError as u, authErrorFromResponse as v };
129
+ export { OtpInvalidError as _, EmailAlreadyHasPasswordError as a, authErrorFromFetchFailure as b, GoogleSignInError as c, InvalidPasswordError as d, MaxAttemptsError as f, OtpExpiredError as g, NoPendingOtpError as h, CaptchaFailedError as i, InvalidCredentialsError as l, NoPasswordSetError as m, AuthError as n, GoogleSignInCancelledError as o, MaxResendsError as p, AuthErrorInit as r, GoogleSignInCancelledReason as s, AccountSuspendedError as t, InvalidEmailError as u, RateLimitedError as v, authErrorFromResponse as x, ResendCooldownError as y };
@@ -131,6 +131,42 @@ var InvalidEmailError = class extends AuthError {
131
131
  this.name = "InvalidEmailError";
132
132
  }
133
133
  };
134
+ /**
135
+ * The hosted Google sign-in ended without a session because of the user or
136
+ * the browser: the popup was blocked, the popup was closed early, or the
137
+ * user cancelled on Google's account chooser. `code` is always
138
+ * `oauth_cancelled`; branch on `reason` for the specific cause.
139
+ */
140
+ var GoogleSignInCancelledError = class extends AuthError {
141
+ reason;
142
+ constructor(init) {
143
+ super({
144
+ status: 0,
145
+ code: "oauth_cancelled",
146
+ serverMessage: `Google sign-in cancelled: ${init.reason}`,
147
+ ...init.cause !== void 0 && { cause: init.cause }
148
+ });
149
+ this.name = "GoogleSignInCancelledError";
150
+ this.reason = init.reason;
151
+ }
152
+ };
153
+ /**
154
+ * The hosted Google sign-in failed. `code` is the failure code the exit or
155
+ * the exchange returned: `invalid_oauth_state`, `invalid_google_code`,
156
+ * `email_unverified`, `oauth_unexpected`, or the SDK-side
157
+ * `oauth_nonce_mismatch`. `status` is the HTTP status when the exchange
158
+ * request failed, otherwise `0`.
159
+ */
160
+ var GoogleSignInError = class extends AuthError {
161
+ constructor(init) {
162
+ super({
163
+ ...init,
164
+ status: init.status ?? 0,
165
+ serverMessage: init.serverMessage ?? `Google sign-in failed: ${init.code}`
166
+ });
167
+ this.name = "GoogleSignInError";
168
+ }
169
+ };
134
170
  function num(d, key, fallback = 0) {
135
171
  const v = d?.[key];
136
172
  return typeof v === "number" ? v : fallback;
@@ -189,6 +225,11 @@ async function authErrorFromResponse(response) {
189
225
  });
190
226
  }
191
227
  case "invalid_email": return new InvalidEmailError(init);
228
+ case "invalid_google_code":
229
+ case "email_unverified": return new GoogleSignInError({
230
+ ...init,
231
+ code
232
+ });
192
233
  default:
193
234
  if (response.status === 429) {
194
235
  const retryAfterSeconds = num(details, "retryAfter") || num(details, "retryAfterSeconds") || Number(response.headers.get("Retry-After") ?? 0);
@@ -212,4 +253,4 @@ function authErrorFromFetchFailure(cause, isTimeout = false) {
212
253
  });
213
254
  }
214
255
  //#endregion
215
- export { authErrorFromResponse as _, InvalidCredentialsError as a, MaxAttemptsError as c, NoPendingOtpError as d, OtpExpiredError as f, authErrorFromFetchFailure as g, ResendCooldownError as h, EmailAlreadyHasPasswordError as i, MaxResendsError as l, RateLimitedError as m, AuthError as n, InvalidEmailError as o, OtpInvalidError as p, CaptchaFailedError as r, InvalidPasswordError as s, AccountSuspendedError as t, NoPasswordSetError as u };
256
+ export { ResendCooldownError as _, GoogleSignInCancelledError as a, InvalidEmailError as c, MaxResendsError as d, NoPasswordSetError as f, RateLimitedError as g, OtpInvalidError as h, EmailAlreadyHasPasswordError as i, InvalidPasswordError as l, OtpExpiredError as m, AuthError as n, GoogleSignInError as o, NoPendingOtpError as p, CaptchaFailedError as r, InvalidCredentialsError as s, AccountSuspendedError as t, MaxAttemptsError as u, authErrorFromFetchFailure as v, authErrorFromResponse as y };
@@ -1,2 +1,2 @@
1
- import { a as GoogleNamespace, c as WalletNamespace, i as EmailPasswordNamespace, l as createAuthClient, n as CreateAuthClientOptions, o as ProactiveRefreshConfig, r as EmailOtpNamespace, s as SubscribeOptions, t as AuthClient, u as AuthFetchInit } from "../index-URk8yf8l.js";
1
+ import { a as GoogleNamespace, c as WalletNamespace, i as EmailPasswordNamespace, l as createAuthClient, n as CreateAuthClientOptions, o as ProactiveRefreshConfig, r as EmailOtpNamespace, s as SubscribeOptions, t as AuthClient, u as AuthFetchInit } from "../index-CFXMA6WD.js";
2
2
  export { AuthClient, AuthFetchInit, CreateAuthClientOptions, EmailOtpNamespace, EmailPasswordNamespace, GoogleNamespace, ProactiveRefreshConfig, SubscribeOptions, WalletNamespace, createAuthClient };
@@ -1,2 +1,2 @@
1
- import { t as createAuthClient } from "../client-DxhQkQcE.js";
1
+ import { t as createAuthClient } from "../client-Bk9WIMVc.js";
2
2
  export { createAuthClient };
@@ -1,5 +1,143 @@
1
- import { _ as authErrorFromResponse, g as authErrorFromFetchFailure, n as AuthError } from "./authError-CYUAl2Jt.js";
1
+ import { a as GoogleSignInCancelledError, n as AuthError, o as GoogleSignInError, v as authErrorFromFetchFailure, y as authErrorFromResponse } from "./authError-CUQ1rFAr.js";
2
2
  import { n as memoryStore } from "./sessionStore-DD6lON9W.js";
3
+ //#region src/client/googleHosted.ts
4
+ const NONCE_STORAGE_KEY = "baliola-auth:google:nonce";
5
+ const MESSAGE_TYPE = "baliola-auth:google";
6
+ const POPUP_WINDOW_NAME = "baliola-auth-google";
7
+ const DEFAULT_POPUP_WIDTH = 500;
8
+ const DEFAULT_POPUP_HEIGHT = 640;
9
+ const POPUP_POLL_INTERVAL_MS = 500;
10
+ function browserWindow() {
11
+ return typeof globalThis.window === "undefined" ? null : globalThis.window;
12
+ }
13
+ function requireBrowserWindow(method) {
14
+ const win = browserWindow();
15
+ if (!win) throw new Error(`google.${method}: only available in a browser (window is undefined)`);
16
+ return win;
17
+ }
18
+ function parseExitMessage(data) {
19
+ if (typeof data !== "object" || data === null) return null;
20
+ const record = data;
21
+ if (record["type"] !== MESSAGE_TYPE) return null;
22
+ const nonce = record["nonce"];
23
+ return {
24
+ nonce: typeof nonce === "string" ? nonce : null,
25
+ ...typeof record["code"] === "string" && { code: record["code"] },
26
+ ...typeof record["error"] === "string" && { error: record["error"] }
27
+ };
28
+ }
29
+ function exitError(code) {
30
+ if (code === "access_denied") return new GoogleSignInCancelledError({ reason: "access_denied" });
31
+ return new GoogleSignInError({ code });
32
+ }
33
+ function createGoogleHosted(ctx) {
34
+ const authOrigin = new URL(ctx.baseUrl).origin;
35
+ function resolveReturnTo(returnTo) {
36
+ if (returnTo !== void 0 && /^https?:\/\//i.test(returnTo)) return returnTo;
37
+ const win = browserWindow();
38
+ if (!win) throw new Error("google.startUrl: returnTo must be an absolute URL outside a browser (window is undefined)");
39
+ if (returnTo === void 0) {
40
+ const current = new URL(win.location.href);
41
+ current.hash = "";
42
+ return current.toString();
43
+ }
44
+ return new URL(returnTo, win.location.href).toString();
45
+ }
46
+ function saveRedirectNonce(nonce) {
47
+ if (typeof globalThis.sessionStorage === "undefined") throw new Error("google.startUrl: sessionStorage is required for redirect mode");
48
+ globalThis.sessionStorage.setItem(NONCE_STORAGE_KEY, nonce);
49
+ }
50
+ function startUrl(opts) {
51
+ if (ctx.clientId === void 0) throw new Error("google.startUrl: clientId is required");
52
+ const url = new URL(`${ctx.baseUrl}/auth/google/start`);
53
+ url.searchParams.set("clientId", ctx.clientId);
54
+ url.searchParams.set("returnTo", resolveReturnTo(opts.returnTo));
55
+ url.searchParams.set("mode", opts.mode);
56
+ url.searchParams.set("nonce", opts.nonce);
57
+ if (opts.mode === "redirect") saveRedirectNonce(opts.nonce);
58
+ return url.toString();
59
+ }
60
+ function signInWithPopup(opts = {}) {
61
+ return new Promise((resolve, reject) => {
62
+ const win = requireBrowserWindow("signInWithPopup");
63
+ const nonce = crypto.randomUUID();
64
+ const url = startUrl({
65
+ mode: "popup",
66
+ nonce,
67
+ ...opts.returnTo !== void 0 && { returnTo: opts.returnTo }
68
+ });
69
+ const width = opts.popup?.width ?? DEFAULT_POPUP_WIDTH;
70
+ const height = opts.popup?.height ?? DEFAULT_POPUP_HEIGHT;
71
+ const popup = win.open(url, POPUP_WINDOW_NAME, `popup,width=${width},height=${height}`);
72
+ if (!popup) {
73
+ reject(new GoogleSignInCancelledError({ reason: "popup_blocked" }));
74
+ return;
75
+ }
76
+ let settled = false;
77
+ let closeTimer = null;
78
+ const cleanup = () => {
79
+ settled = true;
80
+ win.removeEventListener("message", onMessage);
81
+ clearInterval(pollTimer);
82
+ if (closeTimer !== null) clearTimeout(closeTimer);
83
+ };
84
+ const onMessage = (event) => {
85
+ if (settled || event.origin !== authOrigin) return;
86
+ const message = parseExitMessage(event.data);
87
+ if (!message || message.nonce !== nonce) return;
88
+ cleanup();
89
+ if (message.code !== void 0) {
90
+ ctx.exchange({ code: message.code }).then(resolve, reject);
91
+ return;
92
+ }
93
+ reject(exitError(message.error ?? "oauth_unexpected"));
94
+ };
95
+ const pollTimer = setInterval(() => {
96
+ if (settled || !popup.closed || closeTimer !== null) return;
97
+ closeTimer = setTimeout(() => {
98
+ if (settled) return;
99
+ cleanup();
100
+ reject(new GoogleSignInCancelledError({ reason: "popup_closed" }));
101
+ }, POPUP_POLL_INTERVAL_MS);
102
+ }, POPUP_POLL_INTERVAL_MS);
103
+ win.addEventListener("message", onMessage);
104
+ });
105
+ }
106
+ function takeRedirectNonce() {
107
+ if (typeof globalThis.sessionStorage === "undefined") return null;
108
+ const saved = globalThis.sessionStorage.getItem(NONCE_STORAGE_KEY);
109
+ globalThis.sessionStorage.removeItem(NONCE_STORAGE_KEY);
110
+ return saved;
111
+ }
112
+ function stripExitParams(url) {
113
+ for (const key of [
114
+ "code",
115
+ "error",
116
+ "nonce"
117
+ ]) url.searchParams.delete(key);
118
+ if (typeof globalThis.history === "undefined") return;
119
+ globalThis.history.replaceState(globalThis.history.state, "", url.toString());
120
+ }
121
+ async function completeRedirect(opts = {}) {
122
+ const win = requireBrowserWindow("completeRedirect");
123
+ const url = new URL(opts.url ?? win.location.href);
124
+ const code = url.searchParams.get("code");
125
+ const error = url.searchParams.get("error");
126
+ if (code === null && error === null) return null;
127
+ const nonce = url.searchParams.get("nonce");
128
+ const saved = takeRedirectNonce();
129
+ stripExitParams(url);
130
+ if (saved === null || nonce !== saved) throw new GoogleSignInError({ code: "oauth_nonce_mismatch" });
131
+ if (code === null) throw exitError(error ?? "oauth_unexpected");
132
+ return ctx.exchange({ code });
133
+ }
134
+ return {
135
+ startUrl,
136
+ signInWithPopup,
137
+ completeRedirect
138
+ };
139
+ }
140
+ //#endregion
3
141
  //#region src/client/methods.ts
4
142
  function toAuthSession(data) {
5
143
  const issuedAt = Date.now();
@@ -130,7 +268,15 @@ function createMethods(ctx) {
130
268
  path: "/auth/google/login",
131
269
  method: "POST",
132
270
  authMode: "none",
133
- body: withClientId("idToken" in input ? { idToken: input.idToken } : { code: input.code })
271
+ body: withClientId({ idToken: input.idToken })
272
+ }));
273
+ },
274
+ async googleExchange(input) {
275
+ return toAuthSession(await ctx.transport.request({
276
+ path: "/auth/google/exchange",
277
+ method: "POST",
278
+ authMode: "none",
279
+ body: { code: input.code }
134
280
  }));
135
281
  },
136
282
  /** wallet.* */
@@ -441,37 +587,55 @@ function createAuthClient(options) {
441
587
  transport,
442
588
  ...options.clientId !== void 0 && { clientId: options.clientId }
443
589
  });
444
- return {
445
- emailOtp: {
446
- sendLoginCode: (input) => methods.sendLoginCode(input),
447
- async verifyLoginCode(input) {
448
- const session = await methods.verifyLoginCode(input);
449
- await setSession(session);
450
- return session;
451
- },
452
- resendLoginCode: (input) => methods.resendLoginCode(input)
590
+ const emailOtp = {
591
+ sendLoginCode: (input) => methods.sendLoginCode(input),
592
+ async verifyLoginCode(input) {
593
+ const session = await methods.verifyLoginCode(input);
594
+ await setSession(session);
595
+ return session;
453
596
  },
454
- emailPassword: {
455
- register: (input) => methods.register(input),
456
- async verifyRegistrationCode(input) {
457
- const session = await methods.verifyRegistrationCode(input);
458
- await setSession(session);
459
- return session;
460
- },
461
- resendRegistrationCode: (input) => methods.resendRegistrationCode(input),
597
+ resendLoginCode: (input) => methods.resendLoginCode(input)
598
+ };
599
+ const emailPassword = {
600
+ register: (input) => methods.register(input),
601
+ async verifyRegistrationCode(input) {
602
+ const session = await methods.verifyRegistrationCode(input);
603
+ await setSession(session);
604
+ return session;
605
+ },
606
+ resendRegistrationCode: (input) => methods.resendRegistrationCode(input),
607
+ async login(input) {
608
+ const session = await methods.loginWithPassword(input);
609
+ await setSession(session);
610
+ return session;
611
+ },
612
+ setPassword: (input) => methods.setPassword(input),
613
+ changePassword: (input) => methods.changePassword(input)
614
+ };
615
+ async function googleExchange(input) {
616
+ const session = await methods.googleExchange(input);
617
+ await setSession(session);
618
+ return session;
619
+ }
620
+ const googleHosted = createGoogleHosted({
621
+ baseUrl,
622
+ ...options.clientId !== void 0 && { clientId: options.clientId },
623
+ exchange: googleExchange
624
+ });
625
+ return {
626
+ emailOtp,
627
+ emailPassword,
628
+ google: {
462
629
  async login(input) {
463
- const session = await methods.loginWithPassword(input);
630
+ const session = await methods.loginWithGoogle(input);
464
631
  await setSession(session);
465
632
  return session;
466
633
  },
467
- setPassword: (input) => methods.setPassword(input),
468
- changePassword: (input) => methods.changePassword(input)
634
+ startUrl: (opts) => googleHosted.startUrl(opts),
635
+ exchange: googleExchange,
636
+ signInWithPopup: (opts) => googleHosted.signInWithPopup(opts),
637
+ completeRedirect: (opts) => googleHosted.completeRedirect(opts)
469
638
  },
470
- google: { async login(input) {
471
- const session = await methods.loginWithGoogle(input);
472
- await setSession(session);
473
- return session;
474
- } },
475
639
  wallet: {
476
640
  getAddress: async () => (await methods.getWalletAddress()).address,
477
641
  signHash: async (hash) => (await methods.signWalletHash(hash)).signature
@@ -1,2 +1,2 @@
1
- import { _ as authErrorFromFetchFailure, a as EmailAlreadyHasPasswordError, c as InvalidPasswordError, d as NoPasswordSetError, f as NoPendingOtpError, g as ResendCooldownError, h as RateLimitedError, i as CaptchaFailedError, l as MaxAttemptsError, m as OtpInvalidError, n as AuthError, o as InvalidCredentialsError, p as OtpExpiredError, r as AuthErrorInit, s as InvalidEmailError, t as AccountSuspendedError, u as MaxResendsError, v as authErrorFromResponse } from "../authError-DgPEjTfW.js";
2
- export { AccountSuspendedError, AuthError, type AuthErrorInit, CaptchaFailedError, EmailAlreadyHasPasswordError, InvalidCredentialsError, InvalidEmailError, InvalidPasswordError, MaxAttemptsError, MaxResendsError, NoPasswordSetError, NoPendingOtpError, OtpExpiredError, OtpInvalidError, RateLimitedError, ResendCooldownError, authErrorFromFetchFailure, authErrorFromResponse };
1
+ import { _ as OtpInvalidError, a as EmailAlreadyHasPasswordError, b as authErrorFromFetchFailure, c as GoogleSignInError, d as InvalidPasswordError, f as MaxAttemptsError, g as OtpExpiredError, h as NoPendingOtpError, i as CaptchaFailedError, l as InvalidCredentialsError, m as NoPasswordSetError, n as AuthError, o as GoogleSignInCancelledError, p as MaxResendsError, r as AuthErrorInit, s as GoogleSignInCancelledReason, t as AccountSuspendedError, u as InvalidEmailError, v as RateLimitedError, x as authErrorFromResponse, y as ResendCooldownError } from "../authError-CDoEEOP_.js";
2
+ export { AccountSuspendedError, AuthError, type AuthErrorInit, CaptchaFailedError, EmailAlreadyHasPasswordError, GoogleSignInCancelledError, type GoogleSignInCancelledReason, GoogleSignInError, InvalidCredentialsError, InvalidEmailError, InvalidPasswordError, MaxAttemptsError, MaxResendsError, NoPasswordSetError, NoPendingOtpError, OtpExpiredError, OtpInvalidError, RateLimitedError, ResendCooldownError, authErrorFromFetchFailure, authErrorFromResponse };
@@ -1,2 +1,2 @@
1
- import { _ as authErrorFromResponse, a as InvalidCredentialsError, c as MaxAttemptsError, d as NoPendingOtpError, f as OtpExpiredError, g as authErrorFromFetchFailure, h as ResendCooldownError, i as EmailAlreadyHasPasswordError, l as MaxResendsError, m as RateLimitedError, n as AuthError, o as InvalidEmailError, p as OtpInvalidError, r as CaptchaFailedError, s as InvalidPasswordError, t as AccountSuspendedError, u as NoPasswordSetError } from "../authError-CYUAl2Jt.js";
2
- export { AccountSuspendedError, AuthError, CaptchaFailedError, EmailAlreadyHasPasswordError, InvalidCredentialsError, InvalidEmailError, InvalidPasswordError, MaxAttemptsError, MaxResendsError, NoPasswordSetError, NoPendingOtpError, OtpExpiredError, OtpInvalidError, RateLimitedError, ResendCooldownError, authErrorFromFetchFailure, authErrorFromResponse };
1
+ import { _ as ResendCooldownError, a as GoogleSignInCancelledError, c as InvalidEmailError, d as MaxResendsError, f as NoPasswordSetError, g as RateLimitedError, h as OtpInvalidError, i as EmailAlreadyHasPasswordError, l as InvalidPasswordError, m as OtpExpiredError, n as AuthError, o as GoogleSignInError, p as NoPendingOtpError, r as CaptchaFailedError, s as InvalidCredentialsError, t as AccountSuspendedError, u as MaxAttemptsError, v as authErrorFromFetchFailure, y as authErrorFromResponse } from "../authError-CUQ1rFAr.js";
2
+ export { AccountSuspendedError, AuthError, CaptchaFailedError, EmailAlreadyHasPasswordError, GoogleSignInCancelledError, GoogleSignInError, InvalidCredentialsError, InvalidEmailError, InvalidPasswordError, MaxAttemptsError, MaxResendsError, NoPasswordSetError, NoPendingOtpError, OtpExpiredError, OtpInvalidError, RateLimitedError, ResendCooldownError, authErrorFromFetchFailure, authErrorFromResponse };
@@ -1,6 +1,6 @@
1
1
  import { c as ResendCodeResult, l as SendLoginCodeResult, n as AuthSession, r as ErrorHandler, s as RegisterResult, u as SessionChangeHandler } from "./session-Cs_P7ojF.js";
2
2
  import { n as SessionStore } from "./sessionStore-BDdEpbL8.js";
3
- import { a as RegisterInput, c as SendLoginCodeInput, d as VerifyRegistrationCodeInput, i as LoginWithPasswordInput, l as SetPasswordInput, m as ProfileResult, n as ChangePasswordInput, o as ResendLoginCodeInput, r as LoginWithGoogleInput, s as ResendRegistrationCodeInput, u as VerifyLoginCodeInput } from "./requests-jRLgNXyf.js";
3
+ import { a as GoogleSignInWithPopupOptions, c as LoginWithGoogleInput, d as ResendLoginCodeInput, f as ResendRegistrationCodeInput, g as VerifyRegistrationCodeInput, h as VerifyLoginCodeInput, i as GoogleExchangeInput, l as LoginWithPasswordInput, m as SetPasswordInput, n as ChangePasswordInput, p as SendLoginCodeInput, r as GoogleCompleteRedirectOptions, s as GoogleStartOptions, u as RegisterInput, y as ProfileResult } from "./requests-C0WoK341.js";
4
4
 
5
5
  //#region src/client/transport.d.ts
6
6
  type FetchLike = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
@@ -118,19 +118,70 @@ type EmailPasswordNamespace = {
118
118
  /** Google flow. */
119
119
  type GoogleNamespace = {
120
120
  /**
121
- * Sign in with Google. Pass `{ idToken }` from the Google Identity Services
122
- * button or One Tap, or `{ code }` from the OAuth popup code flow
123
- * (`google.accounts.oauth2.initCodeClient`), which the server exchanges
124
- * for the ID token using its client secret.
121
+ * Sign in with a Google ID token from the Google Identity Services button
122
+ * or One Tap. Apps that do not load Google Identity Services should use
123
+ * `signInWithPopup` instead.
125
124
  *
126
- * @throws AuthError with code `invalid_google_code` (401) when the exchange
127
- * fails, `google_code_unsupported` (400) when the server has no
128
- * client secret configured, AccountSuspendedError, AuthError.
129
- * @example
130
- * await auth.google.login({ idToken });
131
- * await auth.google.login({ code });
125
+ * @throws AuthError (401) when the ID token fails verification,
126
+ * GoogleSignInError with code `email_unverified`,
127
+ * AccountSuspendedError, AuthError.
132
128
  */
133
129
  login(input: LoginWithGoogleInput): Promise<AuthSession>;
130
+ /**
131
+ * Build the `GET /auth/google/start` URL for the hosted login. Use it to
132
+ * drive the redirect flow yourself (`location.assign(url)`), or a custom
133
+ * popup. In `redirect` mode the nonce is saved in `sessionStorage` for
134
+ * `completeRedirect` to verify.
135
+ *
136
+ * @throws Error when the client has no `clientId`, when `returnTo` is
137
+ * relative outside a browser, or when `sessionStorage` is missing
138
+ * in `redirect` mode.
139
+ */
140
+ startUrl(opts: GoogleStartOptions & {
141
+ nonce: string;
142
+ }): string;
143
+ /**
144
+ * Exchange the one-time `code` from a hosted login exit for a session.
145
+ * `signInWithPopup` and `completeRedirect` call this for you; call it
146
+ * yourself only when driving `startUrl` manually.
147
+ *
148
+ * @throws GoogleSignInError with code `invalid_google_code` (401) when the
149
+ * code is unknown, expired (60 s), or already used;
150
+ * AccountSuspendedError, AuthError.
151
+ */
152
+ exchange(input: GoogleExchangeInput): Promise<AuthSession>;
153
+ /**
154
+ * Sign in with Google through the auth-hosted flow in a popup. Opens
155
+ * `startUrl` in a popup window, waits for the exit message, exchanges the
156
+ * one-time code, and stores the session. Browser only.
157
+ *
158
+ * @throws GoogleSignInCancelledError (`reason`: `popup_blocked`,
159
+ * `popup_closed`, or `access_denied`), GoogleSignInError with the
160
+ * exit or exchange code, Error outside a browser.
161
+ * @example
162
+ * try {
163
+ * const session = await auth.google.signInWithPopup();
164
+ * } catch (e) {
165
+ * if (e instanceof GoogleSignInCancelledError) return; // user backed out
166
+ * throw e;
167
+ * }
168
+ */
169
+ signInWithPopup(opts?: GoogleSignInWithPopupOptions): Promise<AuthSession>;
170
+ /**
171
+ * Finish a hosted Google login started in `redirect` mode. Call it on the
172
+ * `returnTo` page. Resolves `null` when the URL carries no `code` or
173
+ * `error`, otherwise verifies the nonce saved by `startUrl`, strips
174
+ * `code`, `error`, and `nonce` from the URL, and exchanges the code.
175
+ * Browser only.
176
+ *
177
+ * @throws GoogleSignInError (`oauth_nonce_mismatch`, or the exit or
178
+ * exchange code), GoogleSignInCancelledError (`access_denied`),
179
+ * Error outside a browser.
180
+ * @example
181
+ * const session = await auth.google.completeRedirect();
182
+ * if (session) router.replace('/dashboard');
183
+ */
184
+ completeRedirect(opts?: GoogleCompleteRedirectOptions): Promise<AuthSession | null>;
134
185
  };
135
186
  /** Custodial wallet (Console tier). */
136
187
  type WalletNamespace = {
package/dist/index.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import { a as OtpInfo, c as ResendCodeResult, i as ErrorSource, l as SendLoginCodeResult, n as AuthSession, o as Project, r as ErrorHandler, s as RegisterResult, t as Account, u as SessionChangeHandler } from "./session-Cs_P7ojF.js";
2
- import { a as GoogleNamespace, c as WalletNamespace, i as EmailPasswordNamespace, l as createAuthClient, n as CreateAuthClientOptions, o as ProactiveRefreshConfig, r as EmailOtpNamespace, s as SubscribeOptions, t as AuthClient, u as AuthFetchInit } from "./index-URk8yf8l.js";
2
+ import { a as GoogleNamespace, c as WalletNamespace, i as EmailPasswordNamespace, l as createAuthClient, n as CreateAuthClientOptions, o as ProactiveRefreshConfig, r as EmailOtpNamespace, s as SubscribeOptions, t as AuthClient, u as AuthFetchInit } from "./index-CFXMA6WD.js";
3
3
  import { i as memoryStore, n as SessionStore, r as localStorageStore, t as LocalStorageStoreOptions } from "./sessionStore-BDdEpbL8.js";
4
- import { a as RegisterInput, c as SendLoginCodeInput, d as VerifyRegistrationCodeInput, f as Profile, i as LoginWithPasswordInput, l as SetPasswordInput, m as ProfileResult, n as ChangePasswordInput, o as ResendLoginCodeInput, p as ProfileAccount, r as LoginWithGoogleInput, s as ResendRegistrationCodeInput, t as CaptchaArgs, u as VerifyLoginCodeInput } from "./requests-jRLgNXyf.js";
5
- import { _ as authErrorFromFetchFailure, a as EmailAlreadyHasPasswordError, c as InvalidPasswordError, d as NoPasswordSetError, f as NoPendingOtpError, g as ResendCooldownError, h as RateLimitedError, i as CaptchaFailedError, l as MaxAttemptsError, m as OtpInvalidError, n as AuthError, o as InvalidCredentialsError, p as OtpExpiredError, r as AuthErrorInit, s as InvalidEmailError, t as AccountSuspendedError, u as MaxResendsError, v as authErrorFromResponse } from "./authError-DgPEjTfW.js";
4
+ import { _ as Profile, a as GoogleSignInWithPopupOptions, c as LoginWithGoogleInput, d as ResendLoginCodeInput, f as ResendRegistrationCodeInput, g as VerifyRegistrationCodeInput, h as VerifyLoginCodeInput, i as GoogleExchangeInput, l as LoginWithPasswordInput, m as SetPasswordInput, n as ChangePasswordInput, o as GoogleStartMode, p as SendLoginCodeInput, r as GoogleCompleteRedirectOptions, s as GoogleStartOptions, t as CaptchaArgs, u as RegisterInput, v as ProfileAccount, y as ProfileResult } from "./requests-C0WoK341.js";
5
+ import { _ as OtpInvalidError, a as EmailAlreadyHasPasswordError, b as authErrorFromFetchFailure, c as GoogleSignInError, d as InvalidPasswordError, f as MaxAttemptsError, g as OtpExpiredError, h as NoPendingOtpError, i as CaptchaFailedError, l as InvalidCredentialsError, m as NoPasswordSetError, n as AuthError, o as GoogleSignInCancelledError, p as MaxResendsError, r as AuthErrorInit, s as GoogleSignInCancelledReason, t as AccountSuspendedError, u as InvalidEmailError, v as RateLimitedError, x as authErrorFromResponse, y as ResendCooldownError } from "./authError-CDoEEOP_.js";
6
6
  import { n as AccessTokenPayloadProject, t as AccessTokenPayload } from "./tokens-BXrPLi5B.js";
7
7
 
8
8
  //#region src/types/wallet.d.ts
@@ -16,4 +16,4 @@ type SignHashResult = {
16
16
  address: string;
17
17
  };
18
18
  //#endregion
19
- export { type AccessTokenPayload, type AccessTokenPayloadProject, type Account, AccountSuspendedError, type AuthClient, AuthError, type AuthErrorInit, type AuthFetchInit, type AuthSession, type CaptchaArgs, CaptchaFailedError, type ChangePasswordInput, type CreateAuthClientOptions, EmailAlreadyHasPasswordError, type EmailOtpNamespace, type EmailPasswordNamespace, type ErrorHandler, type ErrorSource, type GoogleNamespace, InvalidCredentialsError, InvalidEmailError, InvalidPasswordError, type LocalStorageStoreOptions, type LoginWithGoogleInput, type LoginWithPasswordInput, MaxAttemptsError, MaxResendsError, NoPasswordSetError, NoPendingOtpError, OtpExpiredError, type OtpInfo, OtpInvalidError, type ProactiveRefreshConfig, type Profile, type ProfileAccount, type ProfileResult, type Project, RateLimitedError, type RegisterInput, type RegisterResult, type ResendCodeResult, ResendCooldownError, type ResendLoginCodeInput, type ResendRegistrationCodeInput, type SendLoginCodeInput, type SendLoginCodeResult, type SessionChangeHandler, type SessionStore, type SetPasswordInput, type SignHashResult, type SubscribeOptions, type VerifyLoginCodeInput, type VerifyRegistrationCodeInput, type WalletAddressResult, type WalletNamespace, authErrorFromFetchFailure, authErrorFromResponse, createAuthClient, localStorageStore, memoryStore };
19
+ export { type AccessTokenPayload, type AccessTokenPayloadProject, type Account, AccountSuspendedError, type AuthClient, AuthError, type AuthErrorInit, type AuthFetchInit, type AuthSession, type CaptchaArgs, CaptchaFailedError, type ChangePasswordInput, type CreateAuthClientOptions, EmailAlreadyHasPasswordError, type EmailOtpNamespace, type EmailPasswordNamespace, type ErrorHandler, type ErrorSource, type GoogleCompleteRedirectOptions, type GoogleExchangeInput, type GoogleNamespace, GoogleSignInCancelledError, type GoogleSignInCancelledReason, GoogleSignInError, type GoogleSignInWithPopupOptions, type GoogleStartMode, type GoogleStartOptions, InvalidCredentialsError, InvalidEmailError, InvalidPasswordError, type LocalStorageStoreOptions, type LoginWithGoogleInput, type LoginWithPasswordInput, MaxAttemptsError, MaxResendsError, NoPasswordSetError, NoPendingOtpError, OtpExpiredError, type OtpInfo, OtpInvalidError, type ProactiveRefreshConfig, type Profile, type ProfileAccount, type ProfileResult, type Project, RateLimitedError, type RegisterInput, type RegisterResult, type ResendCodeResult, ResendCooldownError, type ResendLoginCodeInput, type ResendRegistrationCodeInput, type SendLoginCodeInput, type SendLoginCodeResult, type SessionChangeHandler, type SessionStore, type SetPasswordInput, type SignHashResult, type SubscribeOptions, type VerifyLoginCodeInput, type VerifyRegistrationCodeInput, type WalletAddressResult, type WalletNamespace, authErrorFromFetchFailure, authErrorFromResponse, createAuthClient, localStorageStore, memoryStore };
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { t as createAuthClient } from "./client-DxhQkQcE.js";
2
- import { _ as authErrorFromResponse, a as InvalidCredentialsError, c as MaxAttemptsError, d as NoPendingOtpError, f as OtpExpiredError, g as authErrorFromFetchFailure, h as ResendCooldownError, i as EmailAlreadyHasPasswordError, l as MaxResendsError, m as RateLimitedError, n as AuthError, o as InvalidEmailError, p as OtpInvalidError, r as CaptchaFailedError, s as InvalidPasswordError, t as AccountSuspendedError, u as NoPasswordSetError } from "./authError-CYUAl2Jt.js";
1
+ import { _ as ResendCooldownError, a as GoogleSignInCancelledError, c as InvalidEmailError, d as MaxResendsError, f as NoPasswordSetError, g as RateLimitedError, h as OtpInvalidError, i as EmailAlreadyHasPasswordError, l as InvalidPasswordError, m as OtpExpiredError, n as AuthError, o as GoogleSignInError, p as NoPendingOtpError, r as CaptchaFailedError, s as InvalidCredentialsError, t as AccountSuspendedError, u as MaxAttemptsError, v as authErrorFromFetchFailure, y as authErrorFromResponse } from "./authError-CUQ1rFAr.js";
2
+ import { t as createAuthClient } from "./client-Bk9WIMVc.js";
3
3
  import { n as memoryStore, t as localStorageStore } from "./sessionStore-DD6lON9W.js";
4
- export { AccountSuspendedError, AuthError, CaptchaFailedError, EmailAlreadyHasPasswordError, InvalidCredentialsError, InvalidEmailError, InvalidPasswordError, MaxAttemptsError, MaxResendsError, NoPasswordSetError, NoPendingOtpError, OtpExpiredError, OtpInvalidError, RateLimitedError, ResendCooldownError, authErrorFromFetchFailure, authErrorFromResponse, createAuthClient, localStorageStore, memoryStore };
4
+ export { AccountSuspendedError, AuthError, CaptchaFailedError, EmailAlreadyHasPasswordError, GoogleSignInCancelledError, GoogleSignInError, InvalidCredentialsError, InvalidEmailError, InvalidPasswordError, MaxAttemptsError, MaxResendsError, NoPasswordSetError, NoPendingOtpError, OtpExpiredError, OtpInvalidError, RateLimitedError, ResendCooldownError, authErrorFromFetchFailure, authErrorFromResponse, createAuthClient, localStorageStore, memoryStore };
@@ -60,16 +60,34 @@ type ChangePasswordInput = {
60
60
  currentPassword: string;
61
61
  newPassword: string;
62
62
  };
63
- /**
64
- * Exactly one of the two shapes. `idToken` comes from Google Identity Services
65
- * (`renderButton` / One Tap). `code` is the authorization code from
66
- * `google.accounts.oauth2.initCodeClient` in popup mode; the server exchanges
67
- * it for the ID token, so the client secret never reaches the browser.
68
- */
63
+ /** `idToken` comes from Google Identity Services (`renderButton` / One Tap). */
69
64
  type LoginWithGoogleInput = {
70
65
  idToken: string;
71
- } | {
66
+ };
67
+ /** The one-time code handed to the app by the hosted Google login exit. */
68
+ type GoogleExchangeInput = {
72
69
  code: string;
73
70
  };
71
+ type GoogleStartMode = 'popup' | 'redirect';
72
+ type GoogleStartOptions = {
73
+ /**
74
+ * Where the browser lands after Google. Absolute URL or a path resolved
75
+ * against `window.location`. Its origin must be one of the project's
76
+ * `allowedOrigins`. Default: the current href without its hash.
77
+ */
78
+ returnTo?: string; /** `popup` posts the result to `window.opener`; `redirect` 302s back to `returnTo`. */
79
+ mode: GoogleStartMode; /** Opaque value echoed back on the exit. Supplied by `signInWithPopup`; callers normally omit it. */
80
+ nonce?: string;
81
+ };
82
+ type GoogleSignInWithPopupOptions = {
83
+ /** See `GoogleStartOptions.returnTo`. Default: the current href without its hash. */returnTo?: string;
84
+ popup?: {
85
+ /** Popup width in CSS pixels. Default: 500. */width?: number; /** Popup height in CSS pixels. Default: 640. */
86
+ height?: number;
87
+ };
88
+ };
89
+ type GoogleCompleteRedirectOptions = {
90
+ /** URL to read `code`, `error`, and `nonce` from. Default: `window.location.href`. */url?: string;
91
+ };
74
92
  //#endregion
75
- export { RegisterInput as a, SendLoginCodeInput as c, VerifyRegistrationCodeInput as d, Profile as f, LoginWithPasswordInput as i, SetPasswordInput as l, ProfileResult as m, ChangePasswordInput as n, ResendLoginCodeInput as o, ProfileAccount as p, LoginWithGoogleInput as r, ResendRegistrationCodeInput as s, CaptchaArgs as t, VerifyLoginCodeInput as u };
93
+ export { Profile as _, GoogleSignInWithPopupOptions as a, LoginWithGoogleInput as c, ResendLoginCodeInput as d, ResendRegistrationCodeInput as f, VerifyRegistrationCodeInput as g, VerifyLoginCodeInput as h, GoogleExchangeInput as i, LoginWithPasswordInput as l, SetPasswordInput as m, ChangePasswordInput as n, GoogleStartMode as o, SendLoginCodeInput as p, GoogleCompleteRedirectOptions as r, GoogleStartOptions as s, CaptchaArgs as t, RegisterInput as u, ProfileAccount as v, ProfileResult as y };
@@ -1,4 +1,4 @@
1
1
  import { a as OtpInfo, c as ResendCodeResult, i as ErrorSource, l as SendLoginCodeResult, n as AuthSession, o as Project, r as ErrorHandler, s as RegisterResult, t as Account, u as SessionChangeHandler } from "../session-Cs_P7ojF.js";
2
- import { a as RegisterInput, c as SendLoginCodeInput, d as VerifyRegistrationCodeInput, f as Profile, i as LoginWithPasswordInput, l as SetPasswordInput, m as ProfileResult, n as ChangePasswordInput, o as ResendLoginCodeInput, p as ProfileAccount, r as LoginWithGoogleInput, s as ResendRegistrationCodeInput, t as CaptchaArgs, u as VerifyLoginCodeInput } from "../requests-jRLgNXyf.js";
2
+ import { _ as Profile, a as GoogleSignInWithPopupOptions, c as LoginWithGoogleInput, d as ResendLoginCodeInput, f as ResendRegistrationCodeInput, g as VerifyRegistrationCodeInput, h as VerifyLoginCodeInput, i as GoogleExchangeInput, l as LoginWithPasswordInput, m as SetPasswordInput, n as ChangePasswordInput, o as GoogleStartMode, p as SendLoginCodeInput, r as GoogleCompleteRedirectOptions, s as GoogleStartOptions, t as CaptchaArgs, u as RegisterInput, v as ProfileAccount, y as ProfileResult } from "../requests-C0WoK341.js";
3
3
  import { n as AccessTokenPayloadProject, t as AccessTokenPayload } from "../tokens-BXrPLi5B.js";
4
- export { type AccessTokenPayload, type AccessTokenPayloadProject, type Account, type AuthSession, type CaptchaArgs, type ChangePasswordInput, type ErrorHandler, type ErrorSource, type LoginWithGoogleInput, type LoginWithPasswordInput, type OtpInfo, type Profile, type ProfileAccount, type ProfileResult, type Project, type RegisterInput, type RegisterResult, type ResendCodeResult, type ResendLoginCodeInput, type ResendRegistrationCodeInput, type SendLoginCodeInput, type SendLoginCodeResult, type SessionChangeHandler, type SetPasswordInput, type VerifyLoginCodeInput, type VerifyRegistrationCodeInput };
4
+ export { type AccessTokenPayload, type AccessTokenPayloadProject, type Account, type AuthSession, type CaptchaArgs, type ChangePasswordInput, type ErrorHandler, type ErrorSource, type GoogleCompleteRedirectOptions, type GoogleExchangeInput, type GoogleSignInWithPopupOptions, type GoogleStartMode, type GoogleStartOptions, type LoginWithGoogleInput, type LoginWithPasswordInput, type OtpInfo, type Profile, type ProfileAccount, type ProfileResult, type Project, type RegisterInput, type RegisterResult, type ResendCodeResult, type ResendLoginCodeInput, type ResendRegistrationCodeInput, type SendLoginCodeInput, type SendLoginCodeResult, type SessionChangeHandler, type SetPasswordInput, type VerifyLoginCodeInput, type VerifyRegistrationCodeInput };
@@ -1,4 +1,4 @@
1
- import { t as AuthClient } from "../index-URk8yf8l.js";
1
+ import { t as AuthClient } from "../index-CFXMA6WD.js";
2
2
  import { LocalAccount } from "viem";
3
3
 
4
4
  //#region src/wallet/index.d.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@baliola/auth-sdk",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "Client SDK for Baliola Auth",
5
5
  "keywords": [
6
6
  "auth",