@baliola/auth-sdk 0.2.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.
@@ -0,0 +1,504 @@
1
+ import { _ as authErrorFromResponse, g as authErrorFromFetchFailure, n as AuthError } from "./authError-DbEZJnC4.js";
2
+ import { n as memoryStore } from "./sessionStore-DD6lON9W.js";
3
+ //#region src/client/methods.ts
4
+ function toAuthSession(data) {
5
+ const issuedAt = Date.now();
6
+ return {
7
+ accessToken: data.accessToken,
8
+ refreshToken: data.refreshToken,
9
+ expiresIn: data.expiresIn,
10
+ issuedAt,
11
+ expiresAt: issuedAt + data.expiresIn * 1e3,
12
+ account: data.account,
13
+ ...data.project !== void 0 && { project: data.project },
14
+ roles: data.roles,
15
+ permissions: data.permissions
16
+ };
17
+ }
18
+ function createMethods(ctx) {
19
+ const withClientId = (body) => {
20
+ if (ctx.clientId === void 0) return body;
21
+ return {
22
+ ...body,
23
+ clientId: ctx.clientId
24
+ };
25
+ };
26
+ const stripUndefined = (body) => {
27
+ const out = {};
28
+ for (const [k, v] of Object.entries(body)) if (v !== void 0) out[k] = v;
29
+ return out;
30
+ };
31
+ return {
32
+ async sendLoginCode(input) {
33
+ return ctx.transport.request({
34
+ path: "/auth/email-otp/send-login-code",
35
+ method: "POST",
36
+ authMode: "none",
37
+ body: stripUndefined(withClientId({
38
+ email: input.email,
39
+ captchaToken: input.captchaToken
40
+ }))
41
+ });
42
+ },
43
+ async verifyLoginCode(input) {
44
+ return toAuthSession(await ctx.transport.request({
45
+ path: "/auth/email-otp/verify-login-code",
46
+ method: "POST",
47
+ authMode: "none",
48
+ body: withClientId({
49
+ email: input.email,
50
+ otp: input.code
51
+ })
52
+ }));
53
+ },
54
+ async resendLoginCode(input) {
55
+ return ctx.transport.request({
56
+ path: "/auth/email-otp/resend-login-code",
57
+ method: "POST",
58
+ authMode: "none",
59
+ body: stripUndefined(withClientId({
60
+ email: input.email,
61
+ captchaToken: input.captchaToken
62
+ }))
63
+ });
64
+ },
65
+ async register(input) {
66
+ return ctx.transport.request({
67
+ path: "/auth/email-password/register",
68
+ method: "POST",
69
+ authMode: "none",
70
+ body: stripUndefined(withClientId({
71
+ email: input.email,
72
+ password: input.password,
73
+ captchaToken: input.captchaToken
74
+ }))
75
+ });
76
+ },
77
+ async verifyRegistrationCode(input) {
78
+ return toAuthSession(await ctx.transport.request({
79
+ path: "/auth/email-password/verify-registration-code",
80
+ method: "POST",
81
+ authMode: "none",
82
+ body: withClientId({
83
+ email: input.email,
84
+ otp: input.code
85
+ })
86
+ }));
87
+ },
88
+ async resendRegistrationCode(input) {
89
+ return ctx.transport.request({
90
+ path: "/auth/email-password/resend-registration-code",
91
+ method: "POST",
92
+ authMode: "none",
93
+ body: stripUndefined(withClientId({
94
+ email: input.email,
95
+ captchaToken: input.captchaToken
96
+ }))
97
+ });
98
+ },
99
+ async loginWithPassword(input) {
100
+ return toAuthSession(await ctx.transport.request({
101
+ path: "/auth/email-password/login",
102
+ method: "POST",
103
+ authMode: "none",
104
+ body: stripUndefined(withClientId({
105
+ email: input.email,
106
+ password: input.password,
107
+ captchaToken: input.captchaToken
108
+ }))
109
+ }));
110
+ },
111
+ async setPassword(input) {
112
+ await ctx.transport.request({
113
+ path: "/auth/email-password/set-password",
114
+ method: "POST",
115
+ authMode: "bearer+session",
116
+ body: { password: input.password }
117
+ });
118
+ },
119
+ async changePassword(input) {
120
+ await ctx.transport.request({
121
+ path: "/auth/email-password/change-password",
122
+ method: "POST",
123
+ authMode: "bearer+session",
124
+ body: {
125
+ currentPassword: input.currentPassword,
126
+ newPassword: input.newPassword
127
+ }
128
+ });
129
+ },
130
+ async loginWithGoogle(input) {
131
+ return toAuthSession(await ctx.transport.request({
132
+ path: "/auth/google/login",
133
+ method: "POST",
134
+ authMode: "none",
135
+ body: withClientId({ idToken: input.idToken })
136
+ }));
137
+ },
138
+ async logoutRequest() {
139
+ await ctx.transport.request({
140
+ path: "/auth/logout",
141
+ method: "POST",
142
+ authMode: "bearer+session"
143
+ });
144
+ },
145
+ /**
146
+ * Type-only helper: declares the refresh response shape so consumers
147
+ * pulling the inferred Methods type don't break. Refresh itself is
148
+ * handled by transport.refreshSession() to keep stampede protection.
149
+ */
150
+ refreshResponseShape() {
151
+ throw new Error("refreshResponseShape is a type-only helper");
152
+ }
153
+ };
154
+ }
155
+ //#endregion
156
+ //#region src/client/transport.ts
157
+ /**
158
+ * Minimal fetch wrapper for Baliola Auth: header injection, timeout via
159
+ * AbortController, error mapping to AuthError, and the 401 → /auth/refresh
160
+ * → retry-once stampede-safe flow.
161
+ *
162
+ * Public surface: `request<T>()` for SDK-internal endpoints (returns parsed
163
+ * data of type T or throws AuthError) and `passthroughFetch()` for the
164
+ * consumer escape hatch (returns Response, never throws on consumer-URL
165
+ * non-2xx, throws only when the SDK's own refresh sub-call fails).
166
+ */
167
+ function createTransport(options) {
168
+ const { baseUrl, fetch: fetchImpl, timeoutMs, onRefreshed, onSessionLost, getCurrentSession, shouldProactivelyRefresh } = options;
169
+ let refreshPromise = null;
170
+ function buildAuthHeaders(mode, session) {
171
+ const headers = new Headers();
172
+ headers.set("Content-Type", "application/json");
173
+ headers.set("Accept", "application/json");
174
+ if (!session) return headers;
175
+ switch (mode) {
176
+ case "bearer+session":
177
+ headers.set("Authorization", `Bearer ${session.accessToken}`);
178
+ headers.set("X-Session-ID", session.refreshToken);
179
+ break;
180
+ case "session-only":
181
+ headers.set("X-Session-ID", session.refreshToken);
182
+ break;
183
+ case "bearer-only-passthrough":
184
+ headers.set("Authorization", `Bearer ${session.accessToken}`);
185
+ break;
186
+ case "none": break;
187
+ }
188
+ return headers;
189
+ }
190
+ /**
191
+ * Compose two AbortSignals into one. Uses native AbortSignal.any when
192
+ * available (Node 20.3+, modern browsers, Bun); falls back to a small
193
+ * polyfill otherwise.
194
+ */
195
+ function composeSignals(signals) {
196
+ const real = signals.filter((s) => s !== void 0);
197
+ if (real.length === 0) return new AbortController().signal;
198
+ if (real.length === 1) return real[0];
199
+ if (typeof AbortSignal.any === "function") return AbortSignal.any(real);
200
+ const ctrl = new AbortController();
201
+ for (const s of real) {
202
+ if (s.aborted) {
203
+ ctrl.abort(s.reason);
204
+ return ctrl.signal;
205
+ }
206
+ s.addEventListener("abort", () => ctrl.abort(s.reason), { once: true });
207
+ }
208
+ return ctrl.signal;
209
+ }
210
+ /**
211
+ * Run a single fetch with timeout + consumer signal composition.
212
+ * Returns the raw Response. Network/abort failures become AuthError.
213
+ */
214
+ async function rawFetch(url, init) {
215
+ const timeoutCtrl = new AbortController();
216
+ const timer = setTimeout(() => timeoutCtrl.abort(/* @__PURE__ */ new Error("timeout")), timeoutMs);
217
+ let didTimeout = false;
218
+ timeoutCtrl.signal.addEventListener("abort", () => {
219
+ didTimeout = true;
220
+ }, { once: true });
221
+ try {
222
+ const signal = composeSignals([timeoutCtrl.signal, init.signal]);
223
+ return await fetchImpl(url, {
224
+ ...init,
225
+ signal
226
+ });
227
+ } catch (err) {
228
+ throw authErrorFromFetchFailure(err, didTimeout);
229
+ } finally {
230
+ clearTimeout(timer);
231
+ }
232
+ }
233
+ /**
234
+ * Call POST /auth/refresh. Used by both proactive and reactive paths.
235
+ * Stampede-protected via shared `refreshPromise`.
236
+ */
237
+ function refreshSession() {
238
+ if (refreshPromise) return refreshPromise;
239
+ const current = getCurrentSession();
240
+ if (!current) {
241
+ const err = new AuthError({
242
+ status: 401,
243
+ serverMessage: "No session to refresh"
244
+ });
245
+ onSessionLost();
246
+ return Promise.reject(err);
247
+ }
248
+ refreshPromise = (async () => {
249
+ try {
250
+ const headers = buildAuthHeaders("session-only", current);
251
+ const response = await rawFetch(`${baseUrl}/auth/refresh`, {
252
+ method: "POST",
253
+ headers
254
+ });
255
+ if (!response.ok) {
256
+ const err = await authErrorFromResponse(response);
257
+ await onSessionLost();
258
+ throw err;
259
+ }
260
+ const body = await response.json();
261
+ const issuedAt = Date.now();
262
+ const merged = {
263
+ ...current,
264
+ accessToken: body.data.accessToken,
265
+ refreshToken: body.data.refreshToken,
266
+ issuedAt,
267
+ expiresAt: issuedAt + current.expiresIn * 1e3
268
+ };
269
+ await onRefreshed(merged);
270
+ return merged;
271
+ } catch (err) {
272
+ if (err instanceof AuthError) {
273
+ if (err.status === 0) await onSessionLost();
274
+ throw err;
275
+ }
276
+ await onSessionLost();
277
+ throw authErrorFromFetchFailure(err);
278
+ } finally {
279
+ refreshPromise = null;
280
+ }
281
+ })();
282
+ return refreshPromise;
283
+ }
284
+ /**
285
+ * Internal SDK request helper. Returns parsed `data` of type T from
286
+ * the standard `{ message, data }` envelope. Throws AuthError on any
287
+ * non-2xx after the refresh-retry flow.
288
+ */
289
+ async function request(opts) {
290
+ if (opts.authMode === "bearer+session" && shouldProactivelyRefresh() && !opts.skipAutoRefresh) await refreshSession();
291
+ const url = `${baseUrl}${opts.path}`;
292
+ let response = await rawFetch(url, {
293
+ method: opts.method,
294
+ headers: buildAuthHeaders(opts.authMode, getCurrentSession()),
295
+ ...opts.body !== void 0 && { body: JSON.stringify(opts.body) },
296
+ ...opts.signal !== void 0 && { signal: opts.signal }
297
+ });
298
+ if (response.status === 401 && !opts.skipAutoRefresh && (opts.authMode === "bearer+session" || opts.authMode === "session-only") && getCurrentSession()) {
299
+ await refreshSession();
300
+ response = await rawFetch(url, {
301
+ method: opts.method,
302
+ headers: buildAuthHeaders(opts.authMode, getCurrentSession()),
303
+ ...opts.body !== void 0 && { body: JSON.stringify(opts.body) },
304
+ ...opts.signal !== void 0 && { signal: opts.signal }
305
+ });
306
+ }
307
+ if (!response.ok) throw await authErrorFromResponse(response);
308
+ const text = await response.text();
309
+ if (text.length === 0) return;
310
+ return JSON.parse(text).data;
311
+ }
312
+ /**
313
+ * Consumer-URL escape hatch. Returns the raw Response. Auto-refresh on
314
+ * 401 the same way as internal calls, but:
315
+ * - Does NOT throw on consumer-URL non-2xx; consumer handles via res.ok.
316
+ * - DOES throw AuthError when the SDK's own /auth/refresh sub-call fails.
317
+ * - Adds Authorization header ONLY if a session is loaded; otherwise
318
+ * passes through unauthenticated.
319
+ * - NEVER sends X-Session-ID to the consumer URL.
320
+ */
321
+ async function passthroughFetch(input, init = {}) {
322
+ const { requireAuth, disableRefresh, ...fetchInit } = init;
323
+ if (requireAuth && !getCurrentSession()) throw new AuthError({
324
+ status: 401,
325
+ serverMessage: "No session loaded"
326
+ });
327
+ const session = getCurrentSession();
328
+ if (!disableRefresh && session && shouldProactivelyRefresh()) await refreshSession();
329
+ const composedInit = composeAuthInit(fetchInit, getCurrentSession());
330
+ let response = await rawFetch(toUrlString(input), composedInit);
331
+ if (!disableRefresh && response.status === 401 && getCurrentSession()) {
332
+ await refreshSession();
333
+ const retryInit = composeAuthInit(fetchInit, getCurrentSession());
334
+ response = await rawFetch(toUrlString(input), retryInit);
335
+ }
336
+ return response;
337
+ }
338
+ function composeAuthInit(init, session) {
339
+ const headers = new Headers(init.headers);
340
+ if (session) headers.set("Authorization", `Bearer ${session.accessToken}`);
341
+ const { signal: _signal, ...rest } = init;
342
+ const out = {
343
+ ...rest,
344
+ headers
345
+ };
346
+ if (init.signal) out.signal = init.signal;
347
+ return out;
348
+ }
349
+ function toUrlString(input) {
350
+ if (typeof input === "string") return input;
351
+ if (input instanceof URL) return input.toString();
352
+ return input.url;
353
+ }
354
+ return {
355
+ request,
356
+ passthroughFetch,
357
+ refreshSession
358
+ };
359
+ }
360
+ //#endregion
361
+ //#region src/client/index.ts
362
+ const DEFAULT_TIMEOUT_MS = 15e3;
363
+ const DEFAULT_PROACTIVE_LEAD_TIME_MS = 6e4;
364
+ /**
365
+ * Channel name used to propagate session changes between same-origin tabs
366
+ * via `BroadcastChannel`. The `v1` suffix lets us evolve the wire format
367
+ * without colliding with old tabs running an older SDK.
368
+ */
369
+ const BROADCAST_CHANNEL_NAME = "baliola.auth.session.v1";
370
+ function createAuthClient(options) {
371
+ if (!options.baseUrl) throw new Error("createAuthClient: baseUrl is required");
372
+ const baseUrl = options.baseUrl.replace(/\/+$/, "");
373
+ const store = options.store ?? memoryStore();
374
+ const fetchImpl = options.fetch ?? ((input, init) => globalThis.fetch(input, init));
375
+ const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
376
+ const proactiveLeadTimeMs = options.proactiveRefresh === false ? null : options.proactiveRefresh?.leadTimeMs ?? DEFAULT_PROACTIVE_LEAD_TIME_MS;
377
+ const onError = options.onError ?? ((e, source) => console.error("[auth-sdk]", source, e));
378
+ let currentSession = null;
379
+ const subscribers = /* @__PURE__ */ new Set();
380
+ function notifySubscribers(session) {
381
+ for (const handler of subscribers) callHandler(handler, session, "session-change-handler");
382
+ }
383
+ function callHandler(handler, session, source) {
384
+ try {
385
+ handler(session);
386
+ } catch (e) {
387
+ try {
388
+ onError(e instanceof Error ? e : new Error(String(e)), source);
389
+ } catch {}
390
+ }
391
+ }
392
+ const channel = typeof globalThis.BroadcastChannel !== "undefined" ? new globalThis.BroadcastChannel(BROADCAST_CHANNEL_NAME) : null;
393
+ async function applyRemoteSession(session) {
394
+ currentSession = session;
395
+ await store.set(session);
396
+ notifySubscribers(session);
397
+ }
398
+ async function setSession(session) {
399
+ await applyRemoteSession(session);
400
+ channel?.postMessage({ session });
401
+ }
402
+ channel?.addEventListener("message", (event) => {
403
+ applyRemoteSession(event.data.session).catch((err) => {
404
+ onError(err instanceof Error ? err : new Error(String(err)), "broadcast-channel-message");
405
+ });
406
+ });
407
+ const transport = createTransport({
408
+ baseUrl,
409
+ fetch: fetchImpl,
410
+ timeoutMs,
411
+ getCurrentSession: () => currentSession,
412
+ shouldProactivelyRefresh: () => {
413
+ if (proactiveLeadTimeMs === null) return false;
414
+ if (!currentSession) return false;
415
+ return currentSession.expiresAt - Date.now() < proactiveLeadTimeMs;
416
+ },
417
+ onRefreshed: async (session) => {
418
+ currentSession = session;
419
+ await store.set(session);
420
+ notifySubscribers(session);
421
+ },
422
+ onSessionLost: async () => {
423
+ currentSession = null;
424
+ await store.set(null);
425
+ notifySubscribers(null);
426
+ }
427
+ });
428
+ const methods = createMethods({
429
+ transport,
430
+ ...options.clientId !== void 0 && { clientId: options.clientId }
431
+ });
432
+ return {
433
+ emailOtp: {
434
+ sendLoginCode: (input) => methods.sendLoginCode(input),
435
+ async verifyLoginCode(input) {
436
+ const session = await methods.verifyLoginCode(input);
437
+ await setSession(session);
438
+ return session;
439
+ },
440
+ resendLoginCode: (input) => methods.resendLoginCode(input)
441
+ },
442
+ emailPassword: {
443
+ register: (input) => methods.register(input),
444
+ async verifyRegistrationCode(input) {
445
+ const session = await methods.verifyRegistrationCode(input);
446
+ await setSession(session);
447
+ return session;
448
+ },
449
+ resendRegistrationCode: (input) => methods.resendRegistrationCode(input),
450
+ async login(input) {
451
+ const session = await methods.loginWithPassword(input);
452
+ await setSession(session);
453
+ return session;
454
+ },
455
+ setPassword: (input) => methods.setPassword(input),
456
+ changePassword: (input) => methods.changePassword(input)
457
+ },
458
+ google: { async login(input) {
459
+ const session = await methods.loginWithGoogle(input);
460
+ await setSession(session);
461
+ return session;
462
+ } },
463
+ async refresh() {
464
+ return transport.refreshSession();
465
+ },
466
+ async logout() {
467
+ let serverError;
468
+ try {
469
+ await methods.logoutRequest();
470
+ } catch (e) {
471
+ serverError = e;
472
+ }
473
+ await setSession(null);
474
+ if (serverError !== void 0) throw serverError;
475
+ },
476
+ getSession() {
477
+ return currentSession;
478
+ },
479
+ isAuthenticated() {
480
+ return currentSession !== null;
481
+ },
482
+ async loadSession() {
483
+ const persisted = await store.get();
484
+ currentSession = persisted;
485
+ return persisted;
486
+ },
487
+ onSessionChange(handler, opts) {
488
+ const immediate = opts?.immediate ?? true;
489
+ subscribers.add(handler);
490
+ if (immediate) callHandler(handler, currentSession, "session-change-handler");
491
+ return () => {
492
+ subscribers.delete(handler);
493
+ };
494
+ },
495
+ fetch(input, init) {
496
+ return transport.passthroughFetch(input, init);
497
+ },
498
+ close() {
499
+ channel?.close();
500
+ }
501
+ };
502
+ }
503
+ //#endregion
504
+ export { createAuthClient as t };
@@ -0,0 +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-C5g5jP5l.js";
2
+ export { AccountSuspendedError, AuthError, type AuthErrorInit, CaptchaFailedError, EmailAlreadyHasPasswordError, InvalidCredentialsError, InvalidEmailError, InvalidPasswordError, MaxAttemptsError, MaxResendsError, NoPasswordSetError, NoPendingOtpError, OtpExpiredError, OtpInvalidError, RateLimitedError, ResendCooldownError, authErrorFromFetchFailure, authErrorFromResponse };
@@ -0,0 +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-DbEZJnC4.js";
2
+ export { AccountSuspendedError, AuthError, CaptchaFailedError, EmailAlreadyHasPasswordError, InvalidCredentialsError, InvalidEmailError, InvalidPasswordError, MaxAttemptsError, MaxResendsError, NoPasswordSetError, NoPendingOtpError, OtpExpiredError, OtpInvalidError, RateLimitedError, ResendCooldownError, authErrorFromFetchFailure, authErrorFromResponse };
@@ -0,0 +1,142 @@
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
+ 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, n as ChangePasswordInput, o as ResendLoginCodeInput, r as LoginWithGoogleInput, s as ResendRegistrationCodeInput, u as VerifyLoginCodeInput } from "./requests-eTORIjY5.js";
4
+
5
+ //#region src/client/transport.d.ts
6
+ type FetchLike = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
7
+ /**
8
+ * Init shape accepted by `auth.fetch()`. Extends `RequestInit` with two
9
+ * SDK-specific opt-in flags: `requireAuth` and `disableRefresh`. Both are
10
+ * stripped before the underlying fetch is called.
11
+ */
12
+ type AuthFetchInit = RequestInit & {
13
+ /**
14
+ * If `true`, throw `AuthError({ status: 401 })` before sending when no
15
+ * session is loaded. Saves a wasted round-trip when the consumer URL
16
+ * would have 401-ed anyway.
17
+ */
18
+ requireAuth?: boolean;
19
+ /**
20
+ * If `true`, skip the SDK's automatic session-refresh machinery for
21
+ * this single call — both proactive (pre-flight) and reactive (post-401
22
+ * retry) paths are bypassed. The raw 401 `Response` is returned to the
23
+ * caller. Use for fire-and-forget telemetry or beacons where a stale
24
+ * token shouldn't trigger a refresh round-trip.
25
+ */
26
+ disableRefresh?: boolean;
27
+ };
28
+ //#endregion
29
+ //#region src/client/index.d.ts
30
+ type ProactiveRefreshConfig = false | {
31
+ /** Refresh proactively if `expiresAt - now < leadTimeMs`. Defaults to 60_000 (60s). */leadTimeMs?: number;
32
+ };
33
+ type CreateAuthClientOptions = {
34
+ /** Base URL of the Baliola Auth server (no trailing slash). */baseUrl: string; /** Optional clientId, applied to every auth request that accepts one. */
35
+ clientId?: string;
36
+ /**
37
+ * Pluggable session store. Defaults to `memoryStore()`. Use
38
+ * `localStorageStore()` in browsers for persistence across reloads.
39
+ */
40
+ store?: SessionStore; /** Override the fetch implementation (e.g. for tests). Defaults to globalThis.fetch. */
41
+ fetch?: FetchLike; /** Per-request timeout in ms. Defaults to 15_000. */
42
+ timeoutMs?: number;
43
+ /**
44
+ * Proactively refresh the access token before it expires. Pass `false`
45
+ * to disable; defaults to `{ leadTimeMs: 60_000 }`.
46
+ */
47
+ proactiveRefresh?: ProactiveRefreshConfig;
48
+ /**
49
+ * Receives errors thrown by user code (e.g. session-change handlers).
50
+ * Defaults to `console.error`. Pass a no-op to silence.
51
+ */
52
+ onError?: ErrorHandler;
53
+ };
54
+ type SubscribeOptions = {
55
+ /**
56
+ * If `true` (default), the handler is called synchronously during
57
+ * subscribe with the current session value. Set to `false` for strict
58
+ * future-changes-only semantics.
59
+ */
60
+ immediate?: boolean;
61
+ };
62
+ /** Passwordless flow ("email_otp" provider). */
63
+ type EmailOtpNamespace = {
64
+ /**
65
+ * Send a 6-digit one-time code to the email. Used for passwordless
66
+ * login (existing accounts) or signup (creates a new account on verify).
67
+ *
68
+ * @example
69
+ * const r = await auth.emailOtp.sendLoginCode({ email, captchaToken })
70
+ * // r = { flow: 'login'|'signup', methods: ['password','passwordless'],
71
+ * // otp: { expiresInSeconds, expiresAt, canResendInSeconds, resendsRemaining } }
72
+ *
73
+ * @throws CaptchaFailedError, RateLimitedError, InvalidEmailError, AuthError.
74
+ */
75
+ sendLoginCode(input: SendLoginCodeInput): Promise<SendLoginCodeResult>;
76
+ /**
77
+ * Verify a passwordless login code and return an authenticated session.
78
+ *
79
+ * @throws OtpInvalidError ({ attemptsRemaining, canResendInSeconds }),
80
+ * OtpExpiredError, MaxAttemptsError ({ retryAfterSeconds }),
81
+ * NoPendingOtpError, RateLimitedError, AuthError.
82
+ */
83
+ verifyLoginCode(input: VerifyLoginCodeInput): Promise<AuthSession>;
84
+ /**
85
+ * Resend the verification code for a pending passwordless OTP.
86
+ * Subject to RESEND_COOLDOWN_SECONDS and MAX_RESENDS_PER_OTP.
87
+ *
88
+ * @throws ResendCooldownError, MaxResendsError, NoPendingOtpError,
89
+ * CaptchaFailedError, RateLimitedError, AuthError.
90
+ */
91
+ resendLoginCode(input: ResendLoginCodeInput): Promise<ResendCodeResult>;
92
+ };
93
+ /** Password flow ("email_password" provider). */
94
+ type EmailPasswordNamespace = {
95
+ /**
96
+ * Begin email+password registration. The bcrypt hash is held server-side
97
+ * with the OTP record until the user verifies.
98
+ *
99
+ * @throws EmailAlreadyHasPasswordError, InvalidPasswordError,
100
+ * CaptchaFailedError, RateLimitedError, AuthError.
101
+ */
102
+ register(input: RegisterInput): Promise<RegisterResult>;
103
+ /**
104
+ * Verify the password-registration code, finalize signup, and return a session.
105
+ */
106
+ verifyRegistrationCode(input: VerifyRegistrationCodeInput): Promise<AuthSession>; /** Resend the verification code for a pending password registration. */
107
+ resendRegistrationCode(input: ResendRegistrationCodeInput): Promise<ResendCodeResult>;
108
+ /**
109
+ * Authenticate with email + password.
110
+ *
111
+ * @throws InvalidCredentialsError, NoPasswordSetError,
112
+ * AccountSuspendedError, CaptchaFailedError, AuthError.
113
+ */
114
+ login(input: LoginWithPasswordInput): Promise<AuthSession>; /** Set a password on an existing account (auth required). */
115
+ setPassword(input: SetPasswordInput): Promise<void>; /** Rotate password (auth required); revokes other sessions on success. */
116
+ changePassword(input: ChangePasswordInput): Promise<void>;
117
+ };
118
+ /** Google flow. */
119
+ type GoogleNamespace = {
120
+ login(input: LoginWithGoogleInput): Promise<AuthSession>;
121
+ };
122
+ type AuthClient = {
123
+ emailOtp: EmailOtpNamespace;
124
+ emailPassword: EmailPasswordNamespace;
125
+ google: GoogleNamespace;
126
+ refresh(): Promise<AuthSession>;
127
+ logout(): Promise<void>;
128
+ getSession(): AuthSession | null;
129
+ isAuthenticated(): boolean;
130
+ loadSession(): Promise<AuthSession | null>;
131
+ onSessionChange(handler: SessionChangeHandler, opts?: SubscribeOptions): () => void;
132
+ /**
133
+ * Fetch a consumer URL with `Authorization: Bearer <accessToken>`
134
+ * automatically attached. See AuthFetchInit for `requireAuth` and
135
+ * `disableRefresh` semantics.
136
+ */
137
+ fetch(input: RequestInfo | URL, init?: AuthFetchInit): Promise<Response>; /** Close cross-tab BroadcastChannel listener. Optional. */
138
+ close(): void;
139
+ };
140
+ declare function createAuthClient(options: CreateAuthClientOptions): AuthClient;
141
+ //#endregion
142
+ export { GoogleNamespace as a, createAuthClient as c, EmailPasswordNamespace as i, AuthFetchInit as l, CreateAuthClientOptions as n, ProactiveRefreshConfig as o, EmailOtpNamespace as r, SubscribeOptions as s, AuthClient as t };
@@ -0,0 +1,7 @@
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 createAuthClient, i as EmailPasswordNamespace, l as AuthFetchInit, n as CreateAuthClientOptions, o as ProactiveRefreshConfig, r as EmailOtpNamespace, s as SubscribeOptions, t as AuthClient } from "./index-G-gqveGn.js";
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, i as LoginWithPasswordInput, l as SetPasswordInput, n as ChangePasswordInput, o as ResendLoginCodeInput, r as LoginWithGoogleInput, s as ResendRegistrationCodeInput, t as CaptchaArgs, u as VerifyLoginCodeInput } from "./requests-eTORIjY5.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-C5g5jP5l.js";
6
+ import { n as AccessTokenPayloadProject, t as AccessTokenPayload } from "./tokens-BXrPLi5B.js";
7
+ 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 Project, RateLimitedError, type RegisterInput, type RegisterResult, type ResendCodeResult, ResendCooldownError, type ResendLoginCodeInput, type ResendRegistrationCodeInput, type SendLoginCodeInput, type SendLoginCodeResult, type SessionChangeHandler, type SessionStore, type SetPasswordInput, type SubscribeOptions, type VerifyLoginCodeInput, type VerifyRegistrationCodeInput, authErrorFromFetchFailure, authErrorFromResponse, createAuthClient, localStorageStore, memoryStore };
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ import { t as createAuthClient } from "./client-BcyoQ5Cj.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-DbEZJnC4.js";
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 };