@neondatabase/auth 0.1.0-beta.12 → 0.1.0-beta.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/README.md +20 -1
  2. package/dist/{adapter-core-Bw9mn_AS.d.mts → adapter-core-9F3bfyWA.d.mts} +160 -206
  3. package/dist/{adapter-core-DODfSw9P.mjs → adapter-core-BPv4mLT0.mjs} +160 -36
  4. package/dist/better-auth-react-adapter-BYvAsZdj.d.mts +2168 -0
  5. package/dist/{better-auth-react-adapter-7JyvHiYG.mjs → better-auth-react-adapter-BkeuhSFt.mjs} +1 -6
  6. package/dist/{chunk-5DLVHPZS-Bxj7snpZ-DoVNlsyk.mjs → chunk-5DLVHPZS-Bxj7snpZ-EhdAQJMu.mjs} +2 -2
  7. package/dist/index.d.mts +9 -3
  8. package/dist/index.mjs +1 -1
  9. package/dist/{neon-auth-Bf2NFptR.mjs → neon-auth-BhLZg9v8.mjs} +4 -3
  10. package/dist/next/index.d.mts +47 -58
  11. package/dist/next/index.mjs +8 -8
  12. package/dist/react/adapters/index.d.mts +2 -2
  13. package/dist/react/adapters/index.mjs +1 -1
  14. package/dist/react/index.d.mts +2 -2
  15. package/dist/react/index.mjs +3 -3
  16. package/dist/react/ui/index.mjs +2 -2
  17. package/dist/react/ui/server.mjs +1 -1
  18. package/dist/supabase-adapter-_2wgvfZ3.d.mts +2254 -0
  19. package/dist/{supabase-adapter-DdhH8btX.mjs → supabase-adapter-rl2coLdb.mjs} +9 -41
  20. package/dist/ui/.safelist.html +1 -1
  21. package/dist/ui/css.css +1 -1
  22. package/dist/ui/tailwind.css +1 -0
  23. package/dist/ui/theme-inline.css +39 -0
  24. package/dist/{ui-aMoA-9nq.mjs → ui-C1IRQzLY.mjs} +49 -49
  25. package/dist/vanilla/adapters/index.d.mts +2 -2
  26. package/dist/vanilla/adapters/index.mjs +1 -1
  27. package/dist/vanilla/index.d.mts +2 -2
  28. package/dist/vanilla/index.mjs +1 -1
  29. package/package.json +5 -5
  30. package/dist/better-auth-react-adapter-JoscqoDc.d.mts +0 -722
  31. package/dist/supabase-adapter-Clxlqg1x.d.mts +0 -127
@@ -1,5 +1,6 @@
1
1
  import { getGlobalBroadcastChannel } from "better-auth/client";
2
- import { adminClient, anonymousClient, emailOTPClient, jwtClient, organizationClient } from "better-auth/client/plugins";
2
+ import { adminClient, emailOTPClient, jwtClient, organizationClient } from "better-auth/client/plugins";
3
+ import z from "zod";
3
4
 
4
5
  //#region src/core/in-flight-request-manager.ts
5
6
  /**
@@ -136,16 +137,68 @@ function getJwtExpiration(jwt) {
136
137
  }
137
138
  }
138
139
 
140
+ //#endregion
141
+ //#region src/core/token-cache.ts
142
+ var TokenCache = class {
143
+ cache = null;
144
+ /**
145
+ * Get cached data if not expired.
146
+ * Returns null if cache is empty or expired.
147
+ */
148
+ get() {
149
+ if (!this.cache) return null;
150
+ if (Date.now() > this.cache.expiresAt) {
151
+ this.cache = null;
152
+ return null;
153
+ }
154
+ return this.cache.data;
155
+ }
156
+ /**
157
+ * Set cached data with TTL.
158
+ * If jwt is provided, TTL is calculated from its expiration.
159
+ * Otherwise, uses default SESSION_CACHE_TTL_MS.
160
+ */
161
+ set(data, jwt) {
162
+ const ttl = this.calculateTTL(jwt);
163
+ this.cache = {
164
+ data,
165
+ expiresAt: Date.now() + ttl
166
+ };
167
+ }
168
+ /**
169
+ * Clear the cache.
170
+ */
171
+ clear() {
172
+ this.cache = null;
173
+ }
174
+ /**
175
+ * Check if cache has valid (non-expired) data.
176
+ */
177
+ has() {
178
+ return this.get() !== null;
179
+ }
180
+ /**
181
+ * Calculate cache TTL from JWT expiration.
182
+ * Falls back to default TTL if JWT is invalid or missing.
183
+ */
184
+ calculateTTL(jwt) {
185
+ if (!jwt) return SESSION_CACHE_TTL_MS;
186
+ const exp = getJwtExpiration(jwt);
187
+ if (!exp) return SESSION_CACHE_TTL_MS;
188
+ const now = Date.now();
189
+ const ttl = exp * 1e3 - now - CLOCK_SKEW_BUFFER_MS;
190
+ return Math.max(ttl, 1e3);
191
+ }
192
+ };
193
+
139
194
  //#endregion
140
195
  //#region src/core/session-cache-manager.ts
141
196
  /**
142
197
  * Manages in-memory session cache with TTL expiration.
143
198
  *
144
- * Features:
145
- * - Stores sessions in Better Auth native format
146
- * - Automatic expiration based on JWT token expiration
199
+ * Built on TokenCache, adding session-specific features:
147
200
  * - Invalidation flag for sign-out scenarios
148
- * - TTL calculation with clock skew buffer
201
+ * - Token refresh detection via lastSessionData comparison
149
202
  *
150
203
  * Example:
151
204
  * ```typescript
@@ -155,48 +208,40 @@ function getJwtExpiration(jwt) {
155
208
  * ```
156
209
  */
157
210
  var SessionCacheManager = class {
158
- cache = null;
211
+ cache = new TokenCache();
159
212
  lastSessionData = null;
213
+ invalidated = false;
160
214
  /**
161
215
  * Get cached session if valid and not expired.
162
216
  * Returns null if cache is invalid, expired, or doesn't exist.
163
217
  */
164
218
  getCachedSession() {
165
- if (!this.cache || this.cache.invalidated) return null;
166
- if (Date.now() > this.cache.expiresAt) {
167
- this.clearSessionCache();
168
- return null;
169
- }
170
- return this.cache.data;
219
+ if (this.invalidated) return null;
220
+ return this.cache.get();
171
221
  }
172
222
  /**
173
- * Set cached session with optional TTL.
174
- * If TTL not provided, calculates from JWT expiration.
223
+ * Set cached session with JWT-based TTL.
175
224
  * Skips caching if cache was invalidated (sign-out scenario).
176
225
  */
177
- setCachedSession(data, ttl) {
178
- if (this.cache?.invalidated) return;
179
- this.lastSessionData = this.cache?.data ?? null;
180
- const calculatedTtl = ttl ?? this.calculateCacheTTL(data.session.token);
181
- this.cache = {
182
- data,
183
- expiresAt: Date.now() + calculatedTtl,
184
- invalidated: false
185
- };
226
+ setCachedSession(data) {
227
+ if (this.invalidated) return;
228
+ this.lastSessionData = this.cache.get();
229
+ this.cache.set(data, data.session.token);
186
230
  }
187
231
  /**
188
232
  * Invalidate cache (marks as invalid but doesn't clear).
189
233
  * Useful for sign-out scenarios where in-flight requests should not cache.
190
234
  */
191
235
  invalidateSessionCache() {
192
- if (this.cache) this.cache.invalidated = true;
236
+ this.invalidated = true;
193
237
  }
194
238
  /**
195
239
  * Clear cache completely.
196
240
  */
197
241
  clearSessionCache() {
198
- this.cache = null;
242
+ this.cache.clear();
199
243
  this.lastSessionData = null;
244
+ this.invalidated = false;
200
245
  }
201
246
  /**
202
247
  * Check if token was refreshed by comparing tokens with previous session.
@@ -206,17 +251,45 @@ var SessionCacheManager = class {
206
251
  if (!this.lastSessionData?.session?.token || !data?.session?.token) return false;
207
252
  return this.lastSessionData.session.token !== data.session.token;
208
253
  }
254
+ };
255
+
256
+ //#endregion
257
+ //#region src/core/anonymous-token-cache-manager.ts
258
+ /**
259
+ * Manages in-memory anonymous token cache with TTL expiration.
260
+ *
261
+ * Stores the full anonymous token response (token + expires_at).
262
+ * Unlike SessionCacheManager, doesn't need:
263
+ * - Invalidation flag (no sign-out scenario for anonymous tokens)
264
+ * - Refresh detection (anonymous tokens are stateless)
265
+ */
266
+ var AnonymousTokenCacheManager = class {
267
+ cache = new TokenCache();
209
268
  /**
210
- * Calculate cache TTL from JWT expiration.
211
- * Falls back to default TTL if JWT is invalid or missing.
269
+ * Get cached anonymous token response if not expired.
270
+ * Returns null if cache is empty or expired.
212
271
  */
213
- calculateCacheTTL(jwt) {
214
- if (!jwt) return SESSION_CACHE_TTL_MS;
215
- const exp = getJwtExpiration(jwt);
216
- if (!exp) return SESSION_CACHE_TTL_MS;
217
- const now = Date.now();
218
- const ttl = exp * 1e3 - now - CLOCK_SKEW_BUFFER_MS;
219
- return Math.max(ttl, 1e3);
272
+ getCachedResponse() {
273
+ return this.cache.get();
274
+ }
275
+ /**
276
+ * Set cached anonymous token response with JWT-based TTL.
277
+ * TTL is automatically calculated from the JWT expiration.
278
+ */
279
+ setCachedResponse(data) {
280
+ this.cache.set(data, data.token);
281
+ }
282
+ /**
283
+ * Clear the cache.
284
+ */
285
+ clearCache() {
286
+ this.cache.clear();
287
+ }
288
+ /**
289
+ * Check if cache has a valid (non-expired) response.
290
+ */
291
+ hasCachedResponse() {
292
+ return this.cache.has();
220
293
  }
221
294
  };
222
295
 
@@ -230,11 +303,34 @@ const isBrowser = () => {
230
303
  return globalThis.window !== void 0 && typeof document !== "undefined";
231
304
  };
232
305
 
306
+ //#endregion
307
+ //#region src/plugins/anonymous-token.ts
308
+ const ANONYMOUS_TOKEN_ENDPOINT = "/token/anonymous";
309
+ const anonymousTokenResponseSchema = z.object({
310
+ token: z.string(),
311
+ expires_at: z.number()
312
+ });
313
+ const anonymousTokenClient = () => {
314
+ return {
315
+ id: "anonymous-token",
316
+ pathMethods: { [ANONYMOUS_TOKEN_ENDPOINT]: "GET" },
317
+ getActions: ($fetch) => {
318
+ return { getAnonymousToken: async (fetchOptions) => {
319
+ return await $fetch(ANONYMOUS_TOKEN_ENDPOINT, {
320
+ method: "GET",
321
+ ...fetchOptions
322
+ });
323
+ } };
324
+ }
325
+ };
326
+ };
327
+
233
328
  //#endregion
234
329
  //#region src/core/better-auth-methods.ts
235
330
  const CURRENT_TAB_CLIENT_ID = crypto.randomUUID();
236
331
  const BETTER_AUTH_METHODS_IN_FLIGHT_REQUESTS = new InFlightRequestManager();
237
332
  const BETTER_AUTH_METHODS_CACHE = new SessionCacheManager();
333
+ const BETTER_AUTH_ANONYMOUS_TOKEN_CACHE = new AnonymousTokenCacheManager();
238
334
  const BETTER_AUTH_ENDPOINTS = {
239
335
  signUp: "/sign-up",
240
336
  signIn: "/sign-in",
@@ -242,7 +338,8 @@ const BETTER_AUTH_ENDPOINTS = {
242
338
  updateUser: "/update-user",
243
339
  getSession: "/get-session",
244
340
  token: "/token",
245
- anonymousSignIn: "/sign-in/anonymous"
341
+ anonymousSignIn: "/sign-in/anonymous",
342
+ anonymousToken: "/token/anonymous"
246
343
  };
247
344
  const BETTER_AUTH_METHODS_HOOKS = {
248
345
  signUp: {
@@ -338,6 +435,18 @@ const BETTER_AUTH_METHODS_HOOKS = {
338
435
  }
339
436
  }
340
437
  }
438
+ },
439
+ anonymousToken: {
440
+ beforeRequest: () => {
441
+ const cachedResponse = BETTER_AUTH_ANONYMOUS_TOKEN_CACHE.getCachedResponse();
442
+ if (!cachedResponse) return null;
443
+ return Response.json(cachedResponse, { status: 200 });
444
+ },
445
+ onRequest: () => {},
446
+ onSuccess: (responseData) => {
447
+ const parsed = anonymousTokenResponseSchema.safeParse(responseData);
448
+ if (parsed.success) BETTER_AUTH_ANONYMOUS_TOKEN_CACHE.setCachedResponse(parsed.data);
449
+ }
341
450
  }
342
451
  };
343
452
  /**
@@ -396,6 +505,7 @@ function isSessionResponseData(responseData) {
396
505
  }
397
506
  function deriveBetterAuthMethodFromUrl(url) {
398
507
  if (url.includes("/sign-in/anonymous")) return "anonymousSignIn";
508
+ if (url.includes(BETTER_AUTH_ENDPOINTS.anonymousToken)) return "anonymousToken";
399
509
  if (url.includes(BETTER_AUTH_ENDPOINTS.signIn)) return "signIn";
400
510
  if (url.includes(BETTER_AUTH_ENDPOINTS.signUp)) return "signUp";
401
511
  if (url.includes(BETTER_AUTH_ENDPOINTS.signOut)) return "signOut";
@@ -418,7 +528,7 @@ const supportedBetterAuthClientPlugins = [
418
528
  adminClient(),
419
529
  organizationClient(),
420
530
  emailOTPClient(),
421
- anonymousClient()
531
+ anonymousTokenClient()
422
532
  ];
423
533
  var NeonAuthAdapterCore = class {
424
534
  betterAuthOptions;
@@ -488,6 +598,20 @@ var NeonAuthAdapterCore = class {
488
598
  };
489
599
  initBroadcastChannel();
490
600
  }
601
+ /**
602
+ * Get JWT token for authenticated or anonymous access.
603
+ * Single source of truth for token retrieval logic.
604
+ *
605
+ * @param allowAnonymous - When true, fetches anonymous token if no session exists
606
+ * @returns JWT token string or null if unavailable
607
+ */
608
+ async getJWTToken(allowAnonymous) {
609
+ const client = this.getBetterAuthInstance();
610
+ const session = await client.getSession();
611
+ if (session.data?.session?.token) return session.data.session.token;
612
+ if (allowAnonymous) return (await client.getAnonymousToken()).data?.token ?? null;
613
+ return null;
614
+ }
491
615
  };
492
616
 
493
617
  //#endregion