@absolutejs/auth 0.21.1 → 0.22.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,5 @@
1
+ {
2
+ "permissions": {
3
+ "allow": ["Bash(bun run typecheck:*)", "Bash(bun lint:*)"]
4
+ }
5
+ }
package/CLAUDE.md ADDED
@@ -0,0 +1,91 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## Project Overview
6
+
7
+ Absolute Auth is a TypeScript OAuth2 authentication library for the Elysia web framework. It provides session management, multi-provider OAuth2 support, and route protection utilities. Built for Bun runtime.
8
+
9
+ ## Commands
10
+
11
+ ```bash
12
+ bun run build # Bundle with Bun, generate TypeScript declarations
13
+ bun run typecheck # TypeScript type checking
14
+ bun run format # Prettier formatting
15
+ bun run dev # Watch and run example server
16
+ bun run release # Full pipeline: lint, format, build, publish
17
+
18
+ # Database (example app)
19
+ bun db:push # Drizzle migration push
20
+ bun db:migrate # Custom migration runner
21
+ bun db:studio # Drizzle Studio interface
22
+ ```
23
+
24
+ ## Architecture
25
+
26
+ ### Core Module Pattern
27
+
28
+ Each auth feature (`authorize`, `callback`, `refresh`, `revoke`, `signout`, `userStatus`, `profile`) is a standalone module that returns an Elysia instance. The main `absoluteAuth<UserType>(config)` function composes all modules using Elysia's `.use()` pattern.
29
+
30
+ ### OAuth2 Flow
31
+
32
+ 1. **authorize.ts** - Sets state/code_verifier/origin cookies, redirects to provider
33
+ 2. **callback.ts** - Validates authorization code, exchanges for tokens, creates/retrieves user, stores session
34
+ 3. **userStatus.ts** - Returns current session status
35
+ 4. **refresh.ts** - Refreshes tokens for providers that support it
36
+ 5. **revoke.ts** - Revokes tokens for providers that support it
37
+ 6. **signout.ts** - Cleans up session and cookies
38
+
39
+ ### Session Management
40
+
41
+ - Sessions stored in Elysia state (`sessionStore.ts`)
42
+ - Session ID in httpOnly secure cookie (UUID v4)
43
+ - Two session types: `SessionRecord<UserType>` (authenticated) and `UnregisteredSessionRecord` (during OAuth flow)
44
+ - Always check `expiresAt` timestamp before using session
45
+
46
+ ### Generic UserType Pattern
47
+
48
+ All modules are generic over `<UserType>`. The config requires a `getUser(decoded)` function that returns your user type from decoded token data. This keeps the library agnostic to your user model.
49
+
50
+ ### Event Handler Pattern
51
+
52
+ Lifecycle hooks follow `On<Event><Success|Error>` naming:
53
+ - `OnCallbackSuccess`, `OnCallbackError`
54
+ - `OnAuthorizeError`, `OnRefreshSuccess`, etc.
55
+
56
+ Handlers receive context objects and can return `Response`, status object, or `undefined`.
57
+
58
+ ## Code Conventions
59
+
60
+ ### ESLint Rules (from @absolutejs plugin)
61
+
62
+ - No default exports (except eslint config)
63
+ - Minimum variable name length: 3 characters
64
+ - Enforce sorted exports and object keys
65
+ - Maximum nesting depth enforced
66
+
67
+ ### Formatting
68
+
69
+ - Tabs (width 4), not spaces
70
+ - Single quotes, semicolons
71
+ - Trailing commas: none
72
+ - Print width: 80
73
+
74
+ ### Type Safety
75
+
76
+ - Strict mode enabled
77
+ - Use provided type guards from `typeGuards.ts` for runtime validation
78
+ - Always return typed status responses or Response objects for errors
79
+
80
+ ## Key Files
81
+
82
+ - `src/index.ts` - Main export, composes all auth routes
83
+ - `src/types.ts` - Core type definitions
84
+ - `src/utils.ts` - Session validation, instantiation helpers
85
+ - `src/constants.ts` - Cookie/session duration constants
86
+ - `example/server.ts` - Reference implementation
87
+
88
+ ## Dependencies
89
+
90
+ - **elysia** - Web framework (peer dependency)
91
+ - **citra** - OAuth2 client management (provides provider configs, PKCE utilities)
package/dist/index.js CHANGED
@@ -2087,7 +2087,7 @@ var createOAuth2Client = async (providerName, config) => {
2087
2087
  };
2088
2088
 
2089
2089
  // src/index.ts
2090
- import { Elysia as Elysia10 } from "elysia";
2090
+ import { Elysia as Elysia11 } from "elysia";
2091
2091
 
2092
2092
  // src/authorize.ts
2093
2093
  import { Elysia, t as t2 } from "elysia";
@@ -2102,6 +2102,7 @@ var MILLISECONDS_IN_A_DAY = MILLISECONDS_IN_A_SECOND * SECONDS_IN_A_MINUTE * MIN
2102
2102
  var MILLISECONDS_IN_AN_HOUR = MILLISECONDS_IN_A_MINUTE * MINUTES_IN_AN_HOUR;
2103
2103
  var COOKIE_MINUTES = 30;
2104
2104
  var COOKIE_DURATION = SECONDS_IN_A_MINUTE * COOKIE_MINUTES;
2105
+ var DEFAULT_MAX_SESSIONS = 1e4;
2105
2106
 
2106
2107
  // src/typebox.ts
2107
2108
  import { t } from "elysia";
@@ -2109,6 +2110,19 @@ var userSessionIdTypebox = t.Optional(t.TemplateLiteral("${string}-${string}-${s
2109
2110
  var authProviderOption = t.Enum(Object.fromEntries(Object.keys(providers).filter(isValidProviderOption).map((key) => [key, key])));
2110
2111
 
2111
2112
  // src/authorize.ts
2113
+ var parseReferer = (headerReferer) => {
2114
+ if (!headerReferer)
2115
+ return "/";
2116
+ try {
2117
+ const url = new URL(headerReferer);
2118
+ return url.pathname + url.search;
2119
+ } catch {
2120
+ if (headerReferer.startsWith("/") && !headerReferer.startsWith("//")) {
2121
+ return headerReferer;
2122
+ }
2123
+ return "/";
2124
+ }
2125
+ };
2112
2126
  var authorize = ({
2113
2127
  clientProviders,
2114
2128
  authorizeRoute = "/oauth2/:provider/authorization",
@@ -2129,7 +2143,7 @@ var authorize = ({
2129
2143
  if (!providerConfig)
2130
2144
  return status("Unauthorized", "Client provider not found");
2131
2145
  const { providerInstance, scope, searchParams } = providerConfig;
2132
- const referer = headers["referer"] ?? "/";
2146
+ const referer = parseReferer(headers["referer"]);
2133
2147
  origin_url.set({
2134
2148
  httpOnly: true,
2135
2149
  maxAge: COOKIE_DURATION,
@@ -2175,14 +2189,16 @@ var authorize = ({
2175
2189
  });
2176
2190
  return redirect(authorizationURL.toString());
2177
2191
  } catch (err) {
2192
+ console.error("[authorize] Failed to create authorization URL:", {
2193
+ error: err instanceof Error ? err.message : err,
2194
+ provider,
2195
+ stack: err instanceof Error ? err.stack : undefined
2196
+ });
2178
2197
  await onAuthorizeError?.({
2179
2198
  authProvider: provider,
2180
2199
  error: err
2181
2200
  });
2182
- if (err instanceof Error) {
2183
- return status("Internal Server Error", `${err.message} - ${err.stack ?? ""}`);
2184
- }
2185
- return status("Internal Server Error", `Unknown status: ${err}`);
2201
+ return status("Internal Server Error", "Failed to create authorization URL");
2186
2202
  }
2187
2203
  }, {
2188
2204
  cookie: t2.Cookie({
@@ -2209,6 +2225,8 @@ var sessionStore = () => {
2209
2225
 
2210
2226
  // src/typeGuards.ts
2211
2227
  var isValidUser = (user) => true;
2228
+ var UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
2229
+ var isUserSessionId = (key) => UUID_PATTERN.test(key);
2212
2230
  var isNonEmptyString = (str) => str !== null && str !== undefined && str.trim() !== "";
2213
2231
  var isStatusResponse = (value) => typeof value === "object" && value !== null && ("status" in value) && typeof Reflect.get(value, "status") === "number";
2214
2232
 
@@ -2221,7 +2239,9 @@ var instantiateUserSession = async ({
2221
2239
  tokenResponse,
2222
2240
  providerInstance,
2223
2241
  getUser,
2224
- onNewUser
2242
+ onNewUser,
2243
+ sessionDurationMs = MILLISECONDS_IN_A_DAY,
2244
+ unregisteredSessionDurationMs = MILLISECONDS_IN_AN_HOUR
2225
2245
  }) => {
2226
2246
  let userIdentity;
2227
2247
  let accessToken = tokenResponse.access_token;
@@ -2236,7 +2256,11 @@ var instantiateUserSession = async ({
2236
2256
  userIdentity = await providerInstance.fetchUserProfile(tokenResponse.access_token);
2237
2257
  }
2238
2258
  const userSession = validateSession({ session, user_session_id });
2239
- const userSessionId = getUserSessionId(user_session_id);
2259
+ const userSessionId = getUserSessionId({
2260
+ session,
2261
+ unregisteredSession,
2262
+ user_session_id
2263
+ });
2240
2264
  let user = userSession?.user ?? await getUser(userIdentity);
2241
2265
  const response = user ?? await onNewUser(userIdentity);
2242
2266
  const isRedirectOrStatus = response instanceof Response || isStatusResponse(response);
@@ -2244,7 +2268,7 @@ var instantiateUserSession = async ({
2244
2268
  user = response;
2245
2269
  session[userSessionId] = {
2246
2270
  accessToken,
2247
- expiresAt: Date.now() + MILLISECONDS_IN_A_DAY,
2271
+ expiresAt: Date.now() + sessionDurationMs,
2248
2272
  refreshToken,
2249
2273
  user
2250
2274
  };
@@ -2253,14 +2277,14 @@ var instantiateUserSession = async ({
2253
2277
  const existingUnregistered = unregisteredSession[userSessionId];
2254
2278
  if (existingUnregistered) {
2255
2279
  existingUnregistered.accessToken = accessToken;
2256
- existingUnregistered.expiresAt = Date.now() + MILLISECONDS_IN_AN_HOUR;
2280
+ existingUnregistered.expiresAt = Date.now() + unregisteredSessionDurationMs;
2257
2281
  existingUnregistered.refreshToken = refreshToken;
2258
2282
  existingUnregistered.userIdentity = userIdentity;
2259
2283
  return response;
2260
2284
  }
2261
2285
  unregisteredSession[userSessionId] = {
2262
2286
  accessToken,
2263
- expiresAt: Date.now() + MILLISECONDS_IN_AN_HOUR,
2287
+ expiresAt: Date.now() + unregisteredSessionDurationMs,
2264
2288
  refreshToken,
2265
2289
  userIdentity
2266
2290
  };
@@ -2305,17 +2329,28 @@ var validateSession = ({
2305
2329
  }
2306
2330
  return userSession;
2307
2331
  };
2308
- var getUserSessionId = (user_session_id) => {
2332
+ var clearExistingSession = (existingId, session, unregisteredSession) => {
2333
+ if (session)
2334
+ delete session[existingId];
2335
+ if (unregisteredSession)
2336
+ delete unregisteredSession[existingId];
2337
+ };
2338
+ var getUserSessionId = ({
2339
+ user_session_id,
2340
+ session,
2341
+ unregisteredSession
2342
+ }) => {
2309
2343
  const existingId = user_session_id?.value;
2310
- const userSessionId = isNonEmptyString(existingId) ? existingId : crypto.randomUUID();
2311
- if (existingId === undefined) {
2312
- user_session_id.set({
2313
- httpOnly: true,
2314
- sameSite: "lax",
2315
- secure: true,
2316
- value: userSessionId
2317
- });
2344
+ if (isNonEmptyString(existingId)) {
2345
+ clearExistingSession(existingId, session, unregisteredSession);
2318
2346
  }
2347
+ const userSessionId = crypto.randomUUID();
2348
+ user_session_id.set({
2349
+ httpOnly: true,
2350
+ sameSite: "lax",
2351
+ secure: true,
2352
+ value: userSessionId
2353
+ });
2319
2354
  return userSessionId;
2320
2355
  };
2321
2356
 
@@ -2365,14 +2400,23 @@ var callback = ({
2365
2400
  try {
2366
2401
  tokenResponse = await providerInstance.validateAuthorizationCode(requiresPKCE ? { code, codeVerifier: verifier } : { code });
2367
2402
  } catch (err) {
2403
+ console.error("[callback] Failed to validate authorization code:", {
2404
+ authProvider,
2405
+ error: err instanceof Error ? err.message : err,
2406
+ stack: err instanceof Error ? err.stack : undefined
2407
+ });
2368
2408
  await onCallbackError?.({
2369
2409
  authProvider,
2370
2410
  error: err,
2371
2411
  originUrl
2372
2412
  });
2373
- return err instanceof Error ? status("Internal Server Error", `${err.message} - ${err.stack ?? ""}`) : status("Internal Server Error", `Failed to validate authorization code: Unknown status: ${err}`);
2413
+ return status("Internal Server Error", "Failed to validate authorization code");
2374
2414
  }
2375
- const userSessionId = getUserSessionId(user_session_id);
2415
+ const userSessionId = getUserSessionId({
2416
+ session,
2417
+ unregisteredSession,
2418
+ user_session_id
2419
+ });
2376
2420
  const response = await onCallbackSuccess?.({
2377
2421
  authProvider,
2378
2422
  cookie,
@@ -2447,7 +2491,7 @@ var profile = ({
2447
2491
 
2448
2492
  // src/protectRoute.ts
2449
2493
  import { Elysia as Elysia5, t as t5 } from "elysia";
2450
- var protectRoute = () => new Elysia5().use(sessionStore()).guard({ cookie: t5.Cookie({ user_session_id: userSessionIdTypebox }) }).derive(({ store: { session }, cookie: { user_session_id }, status }) => ({
2494
+ var protectRoutePlugin = () => new Elysia5().use(sessionStore()).guard({ cookie: t5.Cookie({ user_session_id: userSessionIdTypebox }) }).derive(({ store: { session }, cookie: { user_session_id }, status }) => ({
2451
2495
  protectRoute: async (handleAuth, handleAuthFail) => {
2452
2496
  const { user, error } = await getStatus(session, user_session_id);
2453
2497
  if (error) {
@@ -2469,7 +2513,8 @@ var refresh = ({
2469
2513
  clientProviders,
2470
2514
  refreshRoute = "/oauth2/tokens",
2471
2515
  onRefreshSuccess,
2472
- onRefreshError
2516
+ onRefreshError,
2517
+ sessionDurationMs = MILLISECONDS_IN_A_DAY
2473
2518
  }) => new Elysia6().use(sessionStore()).post(refreshRoute, async ({
2474
2519
  status,
2475
2520
  store: { session },
@@ -2504,6 +2549,9 @@ var refresh = ({
2504
2549
  }
2505
2550
  try {
2506
2551
  const tokenResponse = await providerInstance.refreshAccessToken(refreshToken);
2552
+ userSession.accessToken = tokenResponse.access_token;
2553
+ userSession.expiresAt = Date.now() + sessionDurationMs;
2554
+ userSession.refreshToken = tokenResponse.refresh_token ?? userSession.refreshToken;
2507
2555
  await onRefreshSuccess?.({
2508
2556
  authProvider: auth_provider.value,
2509
2557
  tokenResponse
@@ -2512,14 +2560,16 @@ var refresh = ({
2512
2560
  status: 204
2513
2561
  });
2514
2562
  } catch (err) {
2563
+ console.error("[refresh] Failed to refresh token:", {
2564
+ authProvider: auth_provider.value,
2565
+ error: err instanceof Error ? err.message : err,
2566
+ stack: err instanceof Error ? err.stack : undefined
2567
+ });
2515
2568
  await onRefreshError?.({
2516
2569
  authProvider: auth_provider.value,
2517
2570
  error: err
2518
2571
  });
2519
- if (err instanceof Error) {
2520
- return status("Internal Server Error", `Failed to refresh token: ${err.message}`);
2521
- }
2522
- return status("Internal Server Error", `Failed to refresh token: Unknown status: ${err}`);
2572
+ return status("Internal Server Error", "Failed to refresh token");
2523
2573
  }
2524
2574
  }, { cookie: t6.Cookie({ user_session_id: userSessionIdTypebox }) });
2525
2575
 
@@ -2569,23 +2619,128 @@ var revoke = ({
2569
2619
  status: 204
2570
2620
  });
2571
2621
  } catch (err) {
2622
+ console.error("[revoke] Failed to revoke token:", {
2623
+ authProvider: auth_provider.value,
2624
+ error: err instanceof Error ? err.message : err,
2625
+ stack: err instanceof Error ? err.stack : undefined
2626
+ });
2572
2627
  await onRevocationError?.({
2573
2628
  authProvider: auth_provider.value,
2574
2629
  error: err
2575
2630
  });
2576
- if (err instanceof Error) {
2577
- return status("Internal Server Error", `Failed to revoke token: ${err.message}`);
2578
- }
2579
- return status("Internal Server Error", `Failed to revoke token: Unknown status: ${err}`);
2631
+ return status("Internal Server Error", "Failed to revoke token");
2580
2632
  }
2581
2633
  }, { cookie: t7.Cookie({ user_session_id: userSessionIdTypebox }) });
2582
2634
 
2635
+ // src/sessionCleanup.ts
2636
+ import { Elysia as Elysia8 } from "elysia";
2637
+ var sessionCleanup = ({
2638
+ cleanupIntervalMs = MILLISECONDS_IN_AN_HOUR,
2639
+ maxSessions = DEFAULT_MAX_SESSIONS,
2640
+ onSessionCleanup
2641
+ }) => {
2642
+ let intervalId = null;
2643
+ return new Elysia8({ name: "sessionCleanup" }).use(sessionStore()).onStart(({ store: { session, unregisteredSession } }) => {
2644
+ intervalId = setInterval(async () => {
2645
+ await performCleanup(session, unregisteredSession, maxSessions, onSessionCleanup);
2646
+ }, cleanupIntervalMs);
2647
+ }).onStop(() => {
2648
+ if (intervalId) {
2649
+ clearInterval(intervalId);
2650
+ intervalId = null;
2651
+ }
2652
+ }).derive(({ store: { session, unregisteredSession } }) => ({
2653
+ cleanupSessions: async () => {
2654
+ await performCleanup(session, unregisteredSession, maxSessions, onSessionCleanup);
2655
+ }
2656
+ })).as("global");
2657
+ };
2658
+ var collectValidSessionEntries = (session) => {
2659
+ const entries = [];
2660
+ for (const [key, value] of Object.entries(session)) {
2661
+ if (!isUserSessionId(key))
2662
+ continue;
2663
+ entries.push([key, value]);
2664
+ }
2665
+ return entries;
2666
+ };
2667
+ var collectValidUnregisteredEntries = (unregisteredSession) => {
2668
+ const entries = [];
2669
+ for (const [key, value] of Object.entries(unregisteredSession)) {
2670
+ if (!isUserSessionId(key))
2671
+ continue;
2672
+ entries.push([key, value]);
2673
+ }
2674
+ return entries;
2675
+ };
2676
+ var removeExpiredSessions = (validEntries, session, now) => {
2677
+ const removed = new Map;
2678
+ for (const [sessionId, userSession] of validEntries) {
2679
+ if (userSession.expiresAt >= now)
2680
+ continue;
2681
+ removed.set(sessionId, userSession);
2682
+ delete session[sessionId];
2683
+ }
2684
+ return removed;
2685
+ };
2686
+ var removeExpiredUnregisteredSessions = (validEntries, unregisteredSession, now) => {
2687
+ const removed = new Map;
2688
+ for (const [sessionId, unregSession] of validEntries) {
2689
+ if (unregSession.expiresAt >= now)
2690
+ continue;
2691
+ removed.set(sessionId, unregSession);
2692
+ delete unregisteredSession[sessionId];
2693
+ }
2694
+ return removed;
2695
+ };
2696
+ var evictExcessSessions = (remainingEntries, session, maxSessions, removedSessions) => {
2697
+ const excessCount = remainingEntries.length - maxSessions;
2698
+ if (excessCount <= 0)
2699
+ return;
2700
+ const sortedByExpiry = remainingEntries.sort(([, entryA], [, entryB]) => entryA.expiresAt - entryB.expiresAt);
2701
+ const toEvict = sortedByExpiry.slice(0, excessCount);
2702
+ for (const [key, value] of toEvict) {
2703
+ removedSessions.set(key, value);
2704
+ delete session[key];
2705
+ }
2706
+ };
2707
+ var evictExcessUnregisteredSessions = (remainingEntries, unregisteredSession, maxSessions, removedUnregisteredSessions) => {
2708
+ const excessCount = remainingEntries.length - maxSessions;
2709
+ if (excessCount <= 0)
2710
+ return;
2711
+ const sortedByExpiry = remainingEntries.sort(([, entryA], [, entryB]) => entryA.expiresAt - entryB.expiresAt);
2712
+ const toEvict = sortedByExpiry.slice(0, excessCount);
2713
+ for (const [key, value] of toEvict) {
2714
+ removedUnregisteredSessions.set(key, value);
2715
+ delete unregisteredSession[key];
2716
+ }
2717
+ };
2718
+ var performCleanup = async (session, unregisteredSession, maxSessions, onSessionCleanup) => {
2719
+ const now = Date.now();
2720
+ const validSessionEntries = collectValidSessionEntries(session);
2721
+ const removedSessions = removeExpiredSessions(validSessionEntries, session, now);
2722
+ const validUnregisteredEntries = collectValidUnregisteredEntries(unregisteredSession);
2723
+ const removedUnregisteredSessions = removeExpiredUnregisteredSessions(validUnregisteredEntries, unregisteredSession, now);
2724
+ const remainingEntries = validSessionEntries.filter(([key]) => !removedSessions.has(key));
2725
+ evictExcessSessions(remainingEntries, session, maxSessions, removedSessions);
2726
+ const remainingUnregistered = validUnregisteredEntries.filter(([key]) => !removedUnregisteredSessions.has(key));
2727
+ evictExcessUnregisteredSessions(remainingUnregistered, unregisteredSession, maxSessions, removedUnregisteredSessions);
2728
+ try {
2729
+ await onSessionCleanup?.({
2730
+ removedSessions,
2731
+ removedUnregisteredSessions
2732
+ });
2733
+ } catch (err) {
2734
+ console.error("[sessionCleanup] onSessionCleanup handler failed:", err);
2735
+ }
2736
+ };
2737
+
2583
2738
  // src/signout.ts
2584
- import { Elysia as Elysia8, t as t8 } from "elysia";
2739
+ import { Elysia as Elysia9, t as t8 } from "elysia";
2585
2740
  var signout = ({
2586
2741
  signoutRoute = "/oauth2/signout",
2587
2742
  onSignOut
2588
- }) => new Elysia8().use(sessionStore()).delete(signoutRoute, async ({
2743
+ }) => new Elysia9().use(sessionStore()).delete(signoutRoute, async ({
2589
2744
  status,
2590
2745
  store: { session },
2591
2746
  cookie: { user_session_id, auth_provider }
@@ -2606,10 +2761,12 @@ var signout = ({
2606
2761
  userSessionId: user_session_id.value
2607
2762
  });
2608
2763
  } catch (err) {
2609
- if (err instanceof Error) {
2610
- return status("Internal Server Error", `Error: ${err.message} - ${err.stack ?? ""}`);
2611
- }
2612
- return status("Internal Server Error", `Unknown Error: ${err}`);
2764
+ console.error("[signout] Sign out operation failed:", {
2765
+ authProvider: auth_provider.value,
2766
+ error: err instanceof Error ? err.message : err,
2767
+ stack: err instanceof Error ? err.stack : undefined
2768
+ });
2769
+ return status("Internal Server Error", "Sign out operation failed");
2613
2770
  }
2614
2771
  delete session[user_session_id.value];
2615
2772
  user_session_id.remove();
@@ -2622,11 +2779,11 @@ var signout = ({
2622
2779
  });
2623
2780
 
2624
2781
  // src/userStatus.ts
2625
- import { Elysia as Elysia9, t as t9 } from "elysia";
2782
+ import { Elysia as Elysia10, t as t9 } from "elysia";
2626
2783
  var userStatus = ({
2627
2784
  statusRoute = "/oauth2/status",
2628
2785
  onStatus
2629
- }) => new Elysia9().use(sessionStore()).get(statusRoute, async ({ status, cookie: { user_session_id }, store: { session } }) => {
2786
+ }) => new Elysia10().use(sessionStore()).get(statusRoute, async ({ status, cookie: { user_session_id }, store: { session } }) => {
2630
2787
  const { user, error } = await getStatus(session, user_session_id);
2631
2788
  if (error) {
2632
2789
  return status(error.code, error.message);
@@ -2649,6 +2806,9 @@ var absoluteAuth = async ({
2649
2806
  statusRoute,
2650
2807
  refreshRoute,
2651
2808
  revokeRoute,
2809
+ cleanupIntervalMs,
2810
+ maxSessions,
2811
+ sessionDurationMs,
2652
2812
  onAuthorizeSuccess,
2653
2813
  onAuthorizeError,
2654
2814
  onProfileSuccess,
@@ -2660,7 +2820,8 @@ var absoluteAuth = async ({
2660
2820
  onRefreshError,
2661
2821
  onSignOut,
2662
2822
  onRevocationSuccess,
2663
- onRevocationError
2823
+ onRevocationError,
2824
+ onSessionCleanup
2664
2825
  }) => {
2665
2826
  const entryPromises = [];
2666
2827
  for (const [providerName, providerConfig] of Object.entries(providersConfiguration)) {
@@ -2676,7 +2837,11 @@ var absoluteAuth = async ({
2676
2837
  ]));
2677
2838
  }
2678
2839
  const clientProviders = Object.fromEntries(await Promise.all(entryPromises));
2679
- return new Elysia10().use(signout({ onSignOut, signoutRoute })).use(revoke({
2840
+ return new Elysia11().use(sessionCleanup({
2841
+ cleanupIntervalMs,
2842
+ maxSessions,
2843
+ onSessionCleanup
2844
+ })).use(signout({ onSignOut, signoutRoute })).use(revoke({
2680
2845
  clientProviders,
2681
2846
  onRevocationError,
2682
2847
  onRevocationSuccess,
@@ -2685,7 +2850,8 @@ var absoluteAuth = async ({
2685
2850
  clientProviders,
2686
2851
  onRefreshError,
2687
2852
  onRefreshSuccess,
2688
- refreshRoute
2853
+ refreshRoute,
2854
+ sessionDurationMs
2689
2855
  })).use(authorize({
2690
2856
  authorizeRoute,
2691
2857
  clientProviders,
@@ -2701,22 +2867,24 @@ var absoluteAuth = async ({
2701
2867
  onProfileError,
2702
2868
  onProfileSuccess,
2703
2869
  profileRoute
2704
- })).use(protectRoute());
2870
+ })).use(protectRoutePlugin());
2705
2871
  };
2706
2872
  export {
2707
2873
  validateSession,
2708
2874
  userSessionIdTypebox,
2709
2875
  sessionStore,
2876
+ sessionCleanup,
2710
2877
  scopeRequiredProviderOptions,
2711
2878
  revocableProviderOptions,
2712
2879
  refreshableProviderOptions,
2713
2880
  providers,
2714
2881
  providerOptions,
2715
- protectRoute,
2882
+ protectRoutePlugin,
2716
2883
  pkceProviderOptions,
2717
2884
  oidcProviderOptions,
2718
2885
  isValidUser,
2719
2886
  isValidProviderOption,
2887
+ isUserSessionId,
2720
2888
  isRevocableProviderOption,
2721
2889
  isRevocableOAuth2Client,
2722
2890
  isRefreshableProviderOption,
@@ -2734,5 +2902,5 @@ export {
2734
2902
  absoluteAuth
2735
2903
  };
2736
2904
 
2737
- //# debugId=34EE5A8C28DCAFD964756E2164756E21
2905
+ //# debugId=305D4B9D1F128FE664756E2164756E21
2738
2906
  //# sourceMappingURL=index.js.map