@neondatabase/auth 0.1.0-beta.14 → 0.1.0-beta.16
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/README.md +1 -0
- package/dist/{adapter-core-BPv4mLT0.mjs → adapter-core-BQ6ga1zK.mjs} +119 -20
- package/dist/{adapter-core-9F3bfyWA.d.mts → adapter-core-DYWYECKK.d.mts} +16 -8
- package/dist/{better-auth-react-adapter-BkeuhSFt.mjs → better-auth-react-adapter-BLKXYcWM.mjs} +1 -1
- package/dist/{supabase-adapter-_2wgvfZ3.d.mts → better-auth-react-adapter-tKs79AwE.d.mts} +204 -290
- package/dist/constants-2bpp2_-f.mjs +30 -0
- package/dist/index-B6dAIdkW.d.mts +100 -0
- package/dist/index.d.mts +5 -104
- package/dist/index.mjs +2 -1
- package/dist/middleware-DXwLKcbA.mjs +305 -0
- package/dist/neon-auth-B_otuPjh.d.mts +105 -0
- package/dist/{neon-auth-BhLZg9v8.mjs → neon-auth-ClDZNB9a.mjs} +1 -1
- package/dist/next/index.d.mts +8 -104
- package/dist/next/index.mjs +4 -310
- package/dist/next/server/index.d.mts +340 -0
- package/dist/next/server/index.mjs +432 -0
- package/dist/react/adapters/index.d.mts +4 -3
- package/dist/react/adapters/index.mjs +2 -1
- package/dist/react/index.d.mts +5 -4
- package/dist/react/index.mjs +4 -4
- package/dist/react/ui/index.d.mts +1 -1
- package/dist/react/ui/index.mjs +2 -3
- package/dist/react/ui/server.mjs +2 -2
- package/dist/{supabase-adapter-rl2coLdb.mjs → supabase-adapter-Bl576usk.mjs} +2 -1
- package/dist/{better-auth-react-adapter-BYvAsZdj.d.mts → supabase-adapter-DtT0d6It.d.mts} +147 -61
- package/dist/types/index.d.mts +3 -7
- package/dist/ui/css.css +1 -1
- package/dist/ui/theme.css +1 -1
- package/dist/ui-DLtIc4wi.mjs +4 -0
- package/dist/vanilla/adapters/index.d.mts +4 -3
- package/dist/vanilla/adapters/index.mjs +2 -1
- package/dist/vanilla/index.d.mts +4 -3
- package/dist/vanilla/index.mjs +2 -1
- package/llms.txt +157 -0
- package/package.json +7 -2
- package/dist/chunk-5DLVHPZS-Bxj7snpZ-EhdAQJMu.mjs +0 -533
- package/dist/ui-C1IRQzLY.mjs +0 -9449
- /package/dist/{adapters-D0mxG3F-.mjs → adapters-CUvhsAvY.mjs} +0 -0
- /package/dist/{adapters-Df6Dd3KK.mjs → adapters-CivF9wql.mjs} +0 -0
- /package/dist/{better-auth-types-CE4hLv9E.d.mts → better-auth-types-Kq3kGuiz.d.mts} +0 -0
- /package/dist/{index-ClXLQ1fw.d.mts → index-D8dPsry7.d.mts} +0 -0
- /package/dist/{index-BXlAjlSt.d.mts → index-D_HDtZfY.d.mts} +0 -0
- /package/dist/{index-DCQ5Y2ED.d.mts → index-OEBbnNdr.d.mts} +0 -0
package/README.md
CHANGED
|
@@ -242,6 +242,7 @@ For Next.js projects, this package provides built-in integration via `@neondatab
|
|
|
242
242
|
- Importing styles (with or without Tailwind CSS)
|
|
243
243
|
- Accessing session data with `neonAuth()` in server components
|
|
244
244
|
- Using `authClient.useSession()` hook in client components
|
|
245
|
+
- Server-side auth operations with `createAuthServer()` from `@neondatabase/auth/next/server`
|
|
245
246
|
|
|
246
247
|
## CSS for UI Components
|
|
247
248
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { a as NEON_AUTH_POPUP_CALLBACK_ROUTE, c as OAUTH_POPUP_MESSAGE_TYPE, i as NEON_AUTH_POPUP_CALLBACK_PARAM_NAME, l as SESSION_CACHE_TTL_MS, o as NEON_AUTH_POPUP_PARAM_NAME, s as NEON_AUTH_SESSION_VERIFIER_PARAM_NAME, t as CLOCK_SKEW_BUFFER_MS } from "./constants-2bpp2_-f.mjs";
|
|
1
2
|
import { getGlobalBroadcastChannel } from "better-auth/client";
|
|
2
3
|
import { adminClient, emailOTPClient, jwtClient, organizationClient } from "better-auth/client/plugins";
|
|
3
4
|
import z from "zod";
|
|
@@ -100,25 +101,6 @@ var InFlightRequestManager = class {
|
|
|
100
101
|
}
|
|
101
102
|
};
|
|
102
103
|
|
|
103
|
-
//#endregion
|
|
104
|
-
//#region src/core/constants.ts
|
|
105
|
-
/**
|
|
106
|
-
* Session caching configuration constants
|
|
107
|
-
*
|
|
108
|
-
* Uses industry-standard 60s cache TTL (common across auth providers).
|
|
109
|
-
*
|
|
110
|
-
* Note: Token refresh detection is now automatic via Better Auth's
|
|
111
|
-
* fetchOptions.onSuccess callback. No polling is needed.
|
|
112
|
-
*/
|
|
113
|
-
/** Session cache TTL in milliseconds (60 seconds) */
|
|
114
|
-
const SESSION_CACHE_TTL_MS = 6e4;
|
|
115
|
-
/** Clock skew buffer for token expiration checks in milliseconds (10 seconds) */
|
|
116
|
-
const CLOCK_SKEW_BUFFER_MS = 1e4;
|
|
117
|
-
/** Default session expiry duration in milliseconds (1 hour) */
|
|
118
|
-
const DEFAULT_SESSION_EXPIRY_MS = 36e5;
|
|
119
|
-
/** Name of the session verifier parameter in the URL, used for the OAUTH flow */
|
|
120
|
-
const NEON_AUTH_SESSION_VERIFIER_PARAM_NAME = "neon_auth_session_verifier";
|
|
121
|
-
|
|
122
104
|
//#endregion
|
|
123
105
|
//#region src/utils/jwt.ts
|
|
124
106
|
/**
|
|
@@ -293,6 +275,59 @@ var AnonymousTokenCacheManager = class {
|
|
|
293
275
|
}
|
|
294
276
|
};
|
|
295
277
|
|
|
278
|
+
//#endregion
|
|
279
|
+
//#region src/core/oauth-popup.ts
|
|
280
|
+
/**
|
|
281
|
+
* Opens an OAuth popup window and waits for completion.
|
|
282
|
+
*
|
|
283
|
+
* This is used when the app is running inside an iframe, where OAuth
|
|
284
|
+
* redirect flows don't work due to X-Frame-Options/CSP restrictions.
|
|
285
|
+
* The popup completes the OAuth flow and sends a postMessage back
|
|
286
|
+
* with the session verifier needed to fetch the session.
|
|
287
|
+
*
|
|
288
|
+
* @param url - The OAuth authorization URL to open in the popup
|
|
289
|
+
* @returns Promise that resolves with the session verifier when OAuth completes
|
|
290
|
+
* @throws Error if popup is blocked, closed by user, or times out
|
|
291
|
+
*/
|
|
292
|
+
async function openOAuthPopup(url) {
|
|
293
|
+
const timeout = 12e4;
|
|
294
|
+
const pollInterval = 500;
|
|
295
|
+
return new Promise((resolve, reject) => {
|
|
296
|
+
const popup = globalThis.open(url, "neon_oauth_popup", "width=500,height=700,popup=yes");
|
|
297
|
+
if (!popup || popup.closed) {
|
|
298
|
+
reject(/* @__PURE__ */ new Error("Popup blocked. Please allow popups for this site."));
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
const timeoutId = setTimeout(() => {
|
|
302
|
+
cleanup();
|
|
303
|
+
try {
|
|
304
|
+
popup.close();
|
|
305
|
+
} catch {}
|
|
306
|
+
reject(/* @__PURE__ */ new Error("OAuth popup timed out. Please try again."));
|
|
307
|
+
}, timeout);
|
|
308
|
+
const pollId = setInterval(() => {
|
|
309
|
+
try {
|
|
310
|
+
if (popup.closed) {
|
|
311
|
+
cleanup();
|
|
312
|
+
reject(/* @__PURE__ */ new Error("OAuth popup was closed. Please try again."));
|
|
313
|
+
}
|
|
314
|
+
} catch {}
|
|
315
|
+
}, pollInterval);
|
|
316
|
+
function cleanup() {
|
|
317
|
+
clearTimeout(timeoutId);
|
|
318
|
+
clearInterval(pollId);
|
|
319
|
+
globalThis.removeEventListener("message", handleMessage);
|
|
320
|
+
}
|
|
321
|
+
function handleMessage(event) {
|
|
322
|
+
if (event.origin !== globalThis.location.origin) return;
|
|
323
|
+
if (event.data?.type !== OAUTH_POPUP_MESSAGE_TYPE) return;
|
|
324
|
+
cleanup();
|
|
325
|
+
resolve({ verifier: event.data.verifier || null });
|
|
326
|
+
}
|
|
327
|
+
globalThis.addEventListener("message", handleMessage);
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
|
|
296
331
|
//#endregion
|
|
297
332
|
//#region src/utils/browser.ts
|
|
298
333
|
/**
|
|
@@ -302,6 +337,19 @@ var AnonymousTokenCacheManager = class {
|
|
|
302
337
|
const isBrowser = () => {
|
|
303
338
|
return globalThis.window !== void 0 && typeof document !== "undefined";
|
|
304
339
|
};
|
|
340
|
+
/**
|
|
341
|
+
* Checks if the code is running inside an iframe
|
|
342
|
+
* Used to detect embedded contexts where OAuth redirect won't work
|
|
343
|
+
* @returns true if in iframe, false otherwise
|
|
344
|
+
*/
|
|
345
|
+
const isIframe = () => {
|
|
346
|
+
if (!isBrowser()) return false;
|
|
347
|
+
try {
|
|
348
|
+
return globalThis.self !== globalThis.top;
|
|
349
|
+
} catch {
|
|
350
|
+
return true;
|
|
351
|
+
}
|
|
352
|
+
};
|
|
305
353
|
|
|
306
354
|
//#endregion
|
|
307
355
|
//#region src/plugins/anonymous-token.ts
|
|
@@ -341,6 +389,39 @@ const BETTER_AUTH_ENDPOINTS = {
|
|
|
341
389
|
anonymousSignIn: "/sign-in/anonymous",
|
|
342
390
|
anonymousToken: "/token/anonymous"
|
|
343
391
|
};
|
|
392
|
+
/**
|
|
393
|
+
* Handles social sign-in via popup when running inside an iframe.
|
|
394
|
+
* This is necessary because OAuth redirects don't work in iframes due to
|
|
395
|
+
* X-Frame-Options/CSP restrictions from OAuth providers.
|
|
396
|
+
*
|
|
397
|
+
* Flow:
|
|
398
|
+
* 1. Request OAuth URL from server (with disableRedirect)
|
|
399
|
+
* 2. Open popup window with the OAuth URL
|
|
400
|
+
* 3. Wait for popup to complete and send back the session verifier
|
|
401
|
+
* 4. Navigate to callbackURL with verifier - normal page load handles session
|
|
402
|
+
*/
|
|
403
|
+
async function handleSocialSignInViaPopup(input, init) {
|
|
404
|
+
const body = JSON.parse(init?.body || "{}");
|
|
405
|
+
const originalCallbackURL = body.callbackURL || "/";
|
|
406
|
+
const popupCallbackUrl = new URL(NEON_AUTH_POPUP_CALLBACK_ROUTE, globalThis.location.origin);
|
|
407
|
+
popupCallbackUrl.searchParams.set(NEON_AUTH_POPUP_PARAM_NAME, "1");
|
|
408
|
+
popupCallbackUrl.searchParams.set(NEON_AUTH_POPUP_CALLBACK_PARAM_NAME, originalCallbackURL);
|
|
409
|
+
body.callbackURL = popupCallbackUrl.toString();
|
|
410
|
+
body.disableRedirect = true;
|
|
411
|
+
const response = await fetch(input, {
|
|
412
|
+
...init,
|
|
413
|
+
body: JSON.stringify(body)
|
|
414
|
+
});
|
|
415
|
+
const data = await response.json();
|
|
416
|
+
const oauthUrl = data.url;
|
|
417
|
+
if (!oauthUrl) throw new Error("Failed to get OAuth URL");
|
|
418
|
+
const popupResult = await openOAuthPopup(oauthUrl);
|
|
419
|
+
if (!popupResult.verifier) throw new Error("OAuth completed but no session verifier received");
|
|
420
|
+
const navigationUrl = new URL(originalCallbackURL, globalThis.location.origin);
|
|
421
|
+
navigationUrl.searchParams.set(NEON_AUTH_SESSION_VERIFIER_PARAM_NAME, popupResult.verifier);
|
|
422
|
+
globalThis.location.href = navigationUrl.toString();
|
|
423
|
+
return Response.json(data, { status: response.status });
|
|
424
|
+
}
|
|
344
425
|
const BETTER_AUTH_METHODS_HOOKS = {
|
|
345
426
|
signUp: {
|
|
346
427
|
onRequest: () => {},
|
|
@@ -359,6 +440,10 @@ const BETTER_AUTH_METHODS_HOOKS = {
|
|
|
359
440
|
}
|
|
360
441
|
},
|
|
361
442
|
signIn: {
|
|
443
|
+
beforeRequest: (input, init) => {
|
|
444
|
+
if (!(typeof input === "string" ? input : input.toString()).includes("/sign-in/social") || !isIframe()) return null;
|
|
445
|
+
return handleSocialSignInViaPopup(input, init);
|
|
446
|
+
},
|
|
362
447
|
onRequest: () => {},
|
|
363
448
|
onSuccess: (responseData) => {
|
|
364
449
|
if (isSessionResponseData(responseData)) {
|
|
@@ -513,6 +598,20 @@ function deriveBetterAuthMethodFromUrl(url) {
|
|
|
513
598
|
if (url.includes(BETTER_AUTH_ENDPOINTS.getSession) || url.includes(BETTER_AUTH_ENDPOINTS.token)) return "getSession";
|
|
514
599
|
}
|
|
515
600
|
function initBroadcastChannel() {
|
|
601
|
+
if (isBrowser() && globalThis.opener && globalThis.opener !== globalThis) {
|
|
602
|
+
const params = new URLSearchParams(globalThis.location.search);
|
|
603
|
+
if (params.has(NEON_AUTH_POPUP_PARAM_NAME)) {
|
|
604
|
+
const verifier = params.get(NEON_AUTH_SESSION_VERIFIER_PARAM_NAME);
|
|
605
|
+
const originalCallback = params.get(NEON_AUTH_POPUP_CALLBACK_PARAM_NAME);
|
|
606
|
+
globalThis.opener.postMessage({
|
|
607
|
+
type: OAUTH_POPUP_MESSAGE_TYPE,
|
|
608
|
+
verifier,
|
|
609
|
+
originalCallback
|
|
610
|
+
}, "*");
|
|
611
|
+
globalThis.close();
|
|
612
|
+
return;
|
|
613
|
+
}
|
|
614
|
+
}
|
|
516
615
|
getGlobalBroadcastChannel().subscribe((message) => {
|
|
517
616
|
if (message.clientId === CURRENT_TAB_CLIENT_ID) return;
|
|
518
617
|
const trigger = message.data?.trigger;
|
|
@@ -615,4 +714,4 @@ var NeonAuthAdapterCore = class {
|
|
|
615
714
|
};
|
|
616
715
|
|
|
617
716
|
//#endregion
|
|
618
|
-
export {
|
|
717
|
+
export { CURRENT_TAB_CLIENT_ID as i, BETTER_AUTH_METHODS_CACHE as n, BETTER_AUTH_METHODS_HOOKS as r, NeonAuthAdapterCore as t };
|
|
@@ -6,10 +6,22 @@ import * as zod0 from "zod";
|
|
|
6
6
|
import * as jose2 from "jose";
|
|
7
7
|
import * as better_auth454 from "better-auth";
|
|
8
8
|
import * as _better_fetch_fetch266 from "@better-fetch/fetch";
|
|
9
|
+
import { BetterFetchError as BetterFetchError$1 } from "@better-fetch/fetch";
|
|
9
10
|
import * as nanostores7 from "nanostores";
|
|
10
11
|
import * as better_call0 from "better-call";
|
|
11
12
|
import * as better_auth_plugins_email_otp0 from "better-auth/plugins/email-otp";
|
|
13
|
+
import { EmailOTPOptions } from "better-auth/plugins/email-otp";
|
|
14
|
+
import { Invitation, InvitationInput, InvitationStatus, Member, MemberInput, Organization, OrganizationInput, OrganizationRole, Team, TeamInput, TeamMember, TeamMemberInput } from "better-auth/plugins/organization";
|
|
15
|
+
import { JWKOptions, JWSAlgorithms, Jwk, JwtOptions } from "better-auth/plugins/jwt";
|
|
16
|
+
import { AdminOptions, InferAdminRolesFromOption, SessionWithImpersonatedBy, UserWithRole } from "better-auth/plugins/admin";
|
|
12
17
|
|
|
18
|
+
//#region src/types/index.d.ts
|
|
19
|
+
type BetterAuthInstance = ReturnType<typeof createAuthClient$1<{
|
|
20
|
+
plugins: SupportedBetterAuthClientPlugins;
|
|
21
|
+
}> | typeof createAuthClient<{
|
|
22
|
+
plugins: SupportedBetterAuthClientPlugins;
|
|
23
|
+
}>>;
|
|
24
|
+
//#endregion
|
|
13
25
|
//#region src/core/adapter-core.d.ts
|
|
14
26
|
interface NeonAuthAdapterCoreAuthOptions extends Omit<BetterAuthClientOptions, 'plugins'> {}
|
|
15
27
|
declare const supportedBetterAuthClientPlugins: ({
|
|
@@ -1243,7 +1255,7 @@ declare const supportedBetterAuthClientPlugins: ({
|
|
|
1243
1255
|
permission: {
|
|
1244
1256
|
readonly organization?: ("delete" | "update")[] | undefined;
|
|
1245
1257
|
readonly member?: ("delete" | "create" | "update")[] | undefined;
|
|
1246
|
-
readonly invitation?: ("
|
|
1258
|
+
readonly invitation?: ("cancel" | "create")[] | undefined;
|
|
1247
1259
|
readonly team?: ("delete" | "create" | "update")[] | undefined;
|
|
1248
1260
|
readonly ac?: ("delete" | "create" | "update" | "read")[] | undefined;
|
|
1249
1261
|
};
|
|
@@ -1252,7 +1264,7 @@ declare const supportedBetterAuthClientPlugins: ({
|
|
|
1252
1264
|
permissions: {
|
|
1253
1265
|
readonly organization?: ("delete" | "update")[] | undefined;
|
|
1254
1266
|
readonly member?: ("delete" | "create" | "update")[] | undefined;
|
|
1255
|
-
readonly invitation?: ("
|
|
1267
|
+
readonly invitation?: ("cancel" | "create")[] | undefined;
|
|
1256
1268
|
readonly team?: ("delete" | "create" | "update")[] | undefined;
|
|
1257
1269
|
readonly ac?: ("delete" | "create" | "update" | "read")[] | undefined;
|
|
1258
1270
|
};
|
|
@@ -1770,11 +1782,7 @@ declare abstract class NeonAuthAdapterCore {
|
|
|
1770
1782
|
* See CLAUDE.md for architecture details and API mappings.
|
|
1771
1783
|
*/
|
|
1772
1784
|
constructor(betterAuthClientOptions: NeonAuthAdapterCoreAuthOptions);
|
|
1773
|
-
abstract getBetterAuthInstance():
|
|
1774
|
-
plugins: SupportedBetterAuthClientPlugins;
|
|
1775
|
-
}> | typeof createAuthClient<{
|
|
1776
|
-
plugins: SupportedBetterAuthClientPlugins;
|
|
1777
|
-
}>>;
|
|
1785
|
+
abstract getBetterAuthInstance(): BetterAuthInstance;
|
|
1778
1786
|
/**
|
|
1779
1787
|
* Get JWT token for authenticated or anonymous access.
|
|
1780
1788
|
* Single source of truth for token retrieval logic.
|
|
@@ -1785,4 +1793,4 @@ declare abstract class NeonAuthAdapterCore {
|
|
|
1785
1793
|
getJWTToken(allowAnonymous: boolean): Promise<string | null>;
|
|
1786
1794
|
}
|
|
1787
1795
|
//#endregion
|
|
1788
|
-
export { NeonAuthAdapterCoreAuthOptions as n, SupportedBetterAuthClientPlugins as r, NeonAuthAdapterCore as t };
|
|
1796
|
+
export { TeamInput as C, UserWithRole as E, Team as S, TeamMemberInput as T, MemberInput as _, BetterAuthInstance as a, OrganizationRole as b, InferAdminRolesFromOption as c, InvitationStatus as d, JWKOptions as f, Member as g, JwtOptions as h, AdminOptions as i, Invitation as l, Jwk as m, NeonAuthAdapterCoreAuthOptions as n, BetterFetchError$1 as o, JWSAlgorithms as p, SupportedBetterAuthClientPlugins as r, EmailOTPOptions as s, NeonAuthAdapterCore as t, InvitationInput as u, Organization as v, TeamMember as w, SessionWithImpersonatedBy as x, OrganizationInput as y };
|
package/dist/{better-auth-react-adapter-BkeuhSFt.mjs → better-auth-react-adapter-BLKXYcWM.mjs}
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as NeonAuthAdapterCore } from "./adapter-core-
|
|
1
|
+
import { t as NeonAuthAdapterCore } from "./adapter-core-BQ6ga1zK.mjs";
|
|
2
2
|
import { createAuthClient } from "better-auth/react";
|
|
3
3
|
|
|
4
4
|
//#region src/adapters/better-auth-react/better-auth-react-adapter.ts
|