@strivacity/sdk-next 4.0.0-beta.1 → 4.0.0-beta.2

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 CHANGED
@@ -106,7 +106,7 @@ export const sdkOptions: SDKInitConfig = {
106
106
  redirectUri: 'https://your-app.example.com/callback', // callback URL after authentication
107
107
  scopes: ['openid', 'profile', 'email'], // requested user permissions/data
108
108
 
109
- // Omit this line entirely for client-managed sessions
109
+ // Omit these lines entirely for client-managed sessions
110
110
  serverSessionUri: '/auth/login',
111
111
  };
112
112
  ```
@@ -148,10 +148,10 @@ export const DELETE = sdk.handler;
148
148
  | `GET` | `/auth/register` | Starts the registration flow and redirects to the IDP | `302` redirect to IDP |
149
149
  | `GET` | `/auth/callback` | Completes authentication (handles the IDP callback) | `302` redirect or popup close script |
150
150
  | `GET` | `/auth/refresh` | Refreshes the access token | `204 No Content` or `302` redirect |
151
- | `GET` | `/auth/revoke` | Revokes tokens and clears the session | `204 No Content` |
152
- | `GET` | `/auth/logout` | Ends the session and redirects to the IDP logout page | `302` redirect to IDP logout |
153
- | `GET` | `/auth/entry` | Handles external flow entry (e.g., password reset link) - embedded/native modes only | JSON with session data |
154
- | `POST` | `/auth/backchannel-logout` | Processes back-channel logout requests from the IDP | `204 No Content` |
151
+ | `GET` | `/auth/revoke` | Revokes tokens and clears the session | `302` redirect to `postLogoutRedirectUri` |
152
+ | `GET` | `/auth/logout` | Ends the session and redirects to the IDP logout page; accepts a same-origin `?returnTo=` (default: `postLogoutRedirectUri`) | `302` to IDP logout (straight to `returnTo` when the session has no ID token) |
153
+ | `GET` | `/auth/entry` | Handles external flow entry (e.g., password reset link) - embedded/native modes only | `302` redirect to `loginUri` |
154
+ | `POST` | `/auth/backchannel-logout` | Processes back-channel logout requests from the IDP | `200 OK` (`400` invalid token, `501` storage without `deleteByLogoutToken`, `500` delete failed) |
155
155
 
156
156
  > The `/auth` prefix and route names come from `authUrlPrefix` - see [Server configuration reference](#server-configuration-reference).
157
157
 
@@ -198,13 +198,14 @@ For server-managed sessions, fetch the session once in your root layout (a Serve
198
198
  ```tsx
199
199
  // app/layout.tsx
200
200
  import type { ReactNode } from 'react';
201
+ import { toClientSession } from '@strivacity/sdk-next/server';
201
202
  import { AuthProvider } from '../lib/auth/provider';
202
203
  import { sdk } from '../lib/auth/server';
203
204
 
204
205
  export const dynamic = 'force-dynamic';
205
206
 
206
207
  export default async function RootLayout({ children }: { children: ReactNode }) {
207
- const session = await sdk.getSession();
208
+ const session = toClientSession(await sdk.getSession());
208
209
 
209
210
  return (
210
211
  <html lang="en-US">
@@ -216,6 +217,8 @@ export default async function RootLayout({ children }: { children: ReactNode })
216
217
  }
217
218
  ```
218
219
 
220
+ > **Note:** The session passed to the provider is serialized into the rendered HTML, so `toClientSession()` (exported from both `@strivacity/sdk-next/server` and `@strivacity/sdk-next/client`) removes the long-lived credentials before handing it over: the refresh token (refresh goes through `/auth/refresh` on the server) and the ID token (only the server-side `/auth/logout` route needs it).
221
+
219
222
  ---
220
223
 
221
224
  ## Client SDK
@@ -415,7 +418,7 @@ export default function LogoutPage() {
415
418
 
416
419
  **Server-managed sessions**:
417
420
 
418
- With `serverSessionUri` configured, redirect to `/auth/logout` instead - the Server SDK clears the session and redirects to the IDP end-session endpoint:
421
+ With `serverSessionUri` configured, the `logout()` call above doesn't clear the server session cookie, so redirect to `/auth/logout` instead - the Server SDK clears the session and redirects to the IDP end-session endpoint, which then sends the user back to `postLogoutRedirectUri`. To land somewhere else, add a same-origin `?returnTo=` (e.g. `/auth/logout?returnTo=/goodbye`); a missing, invalid, or cross-origin value falls back to `postLogoutRedirectUri`. Whichever URL is used must be registered as an allowed post-logout redirect URI:
419
422
 
420
423
  ```tsx
421
424
  // app/logout/page.tsx
@@ -468,7 +471,7 @@ export function TokenPanel() {
468
471
 
469
472
  **Server-managed sessions**:
470
473
 
471
- With `serverSessionUri` configured, tokens are refreshed/revoked by the Server SDK - trigger it by navigating to the catch-all route, then let it redirect back:
474
+ With `serverSessionUri` configured, tokens are refreshed/revoked by the Server SDK - trigger it by navigating to the catch-all route, then let it redirect back. `sdk.refresh({ returnTo: '/profile' })` (`sdk` from `useStrivacity()`) performs the same refresh navigation for you:
472
475
 
473
476
  ```tsx
474
477
  'use client';
@@ -568,11 +571,39 @@ Popup mode always needs client-side JavaScript to open the window, so there's no
568
571
 
569
572
  **Client-managed sessions**:
570
573
 
571
- The popup resolves automatically - no callback page is needed. Token exchange happens inside the popup and the result is posted back to the opener window.
574
+ The pop-up still navigates to your `redirectUri`, so you still need a callback page there - without it nothing posts the result back to the opener. Call `handleCallback()` on that page; in popup mode it never resolves (the opener closes the pop-up once it receives the result), so don't rely on code after it running:
575
+
576
+ ```tsx
577
+ // app/callback/page.tsx
578
+ 'use client';
579
+
580
+ import { useEffect } from 'react';
581
+ import { useStrivacity } from '@strivacity/sdk-next/client';
582
+
583
+ export default function CallbackPage() {
584
+ const { loading, handleCallback } = useStrivacity();
585
+
586
+ useEffect(() => {
587
+ if (loading) {
588
+ return;
589
+ }
590
+
591
+ void handleCallback();
592
+ }, [loading]);
593
+
594
+ return (
595
+ <section>
596
+ <h1>Logging in...</h1>
597
+ </section>
598
+ );
599
+ }
600
+ ```
601
+
602
+ `login()` resolves in the opener once the result has been received and, for client-managed sessions, the tokens have been exchanged.
572
603
 
573
604
  **Server-managed sessions**:
574
605
 
575
- Same as client managed - the popup's internal callback request is also transparently proxied through `/auth/callback`, and the result is posted back to the opener window exactly the same way.
606
+ The callback page must not call `handleCallback()`: forward the query string to `/auth/callback` instead, as in the server-managed redirect callback. The Server SDK exchanges the code, sets the session cookie and responds with a page that posts the result to the opener and closes the pop-up.
576
607
 
577
608
  ##### Registration
578
609
 
@@ -665,7 +696,7 @@ export default function LogoutPage() {
665
696
 
666
697
  **Server-managed sessions**:
667
698
 
668
- With `serverSessionUri` configured, redirect to `/auth/logout` instead - the Server SDK clears the session and redirects to the IDP end-session endpoint:
699
+ With `serverSessionUri` configured, the `logout()` call above doesn't clear the server session cookie, so redirect to `/auth/logout` instead - the Server SDK clears the session and redirects to the IDP end-session endpoint, which then sends the user back to `postLogoutRedirectUri`. To land somewhere else, add a same-origin `?returnTo=` (e.g. `/auth/logout?returnTo=/goodbye`); a missing, invalid, or cross-origin value falls back to `postLogoutRedirectUri`. Whichever URL is used must be registered as an allowed post-logout redirect URI:
669
700
 
670
701
  ```tsx
671
702
  // app/logout/page.tsx
@@ -718,7 +749,7 @@ export function TokenPanel() {
718
749
 
719
750
  **Server-managed sessions**:
720
751
 
721
- With `serverSessionUri` configured, tokens are refreshed/revoked by the Server SDK - trigger it by navigating to the catch-all route, then let it redirect back:
752
+ With `serverSessionUri` configured, tokens are refreshed/revoked by the Server SDK - trigger it by navigating to the catch-all route, then let it redirect back. `sdk.refresh({ returnTo: '/profile' })` (`sdk` from `useStrivacity()`) performs the same refresh navigation for you:
722
753
 
723
754
  ```tsx
724
755
  'use client';
@@ -1246,7 +1277,7 @@ export default function LogoutPage() {
1246
1277
 
1247
1278
  **Server-managed sessions**:
1248
1279
 
1249
- With `serverSessionUri` configured, redirect to `/auth/logout` instead - the Server SDK clears the session and redirects to the IDP end-session endpoint:
1280
+ With `serverSessionUri` configured, the `logout()` call above doesn't clear the server session cookie, so redirect to `/auth/logout` instead - the Server SDK clears the session and redirects to the IDP end-session endpoint, which then sends the user back to `postLogoutRedirectUri`. To land somewhere else, add a same-origin `?returnTo=` (e.g. `/auth/logout?returnTo=/goodbye`); a missing, invalid, or cross-origin value falls back to `postLogoutRedirectUri`. Whichever URL is used must be registered as an allowed post-logout redirect URI:
1250
1281
 
1251
1282
  ```tsx
1252
1283
  // app/logout/page.tsx
@@ -1299,7 +1330,7 @@ export function TokenPanel() {
1299
1330
 
1300
1331
  **Server-managed sessions**:
1301
1332
 
1302
- With `serverSessionUri` configured, tokens are refreshed/revoked by the Server SDK - trigger it by navigating to the catch-all route, then let it redirect back:
1333
+ With `serverSessionUri` configured, tokens are refreshed/revoked by the Server SDK - trigger it by navigating to the catch-all route, then let it redirect back. `sdk.refresh({ returnTo: '/profile' })` (`sdk` from `useStrivacity()`) performs the same refresh navigation for you:
1303
1334
 
1304
1335
  ```tsx
1305
1336
  'use client';
@@ -1353,7 +1384,6 @@ export default function LoginPage() {
1353
1384
  params: {
1354
1385
  prompt: 'login', // use 'create' to open the registration flow instead
1355
1386
  language: 'en-US', // set the UI language (BCP 47 language tag)
1356
- sdk: 'web-minimal', // rendering mode: 'web-minimal' for simplified rendering, 'web' (default) for full rendering hints and branding
1357
1387
  sessionId: searchParams.get('session_id'), // pass a session ID to resume an existing flow
1358
1388
  },
1359
1389
  onLogin: async () => {
@@ -1604,7 +1634,7 @@ export default function LogoutPage() {
1604
1634
 
1605
1635
  **Server-managed sessions**:
1606
1636
 
1607
- With `serverSessionUri` configured, redirect to `/auth/logout` instead - the Server SDK clears the session and redirects to the IDP end-session endpoint:
1637
+ With `serverSessionUri` configured, the `logout()` call above doesn't clear the server session cookie, so redirect to `/auth/logout` instead - the Server SDK clears the session and redirects to the IDP end-session endpoint, which then sends the user back to `postLogoutRedirectUri`. To land somewhere else, add a same-origin `?returnTo=` (e.g. `/auth/logout?returnTo=/goodbye`); a missing, invalid, or cross-origin value falls back to `postLogoutRedirectUri`. Whichever URL is used must be registered as an allowed post-logout redirect URI:
1608
1638
 
1609
1639
  ```tsx
1610
1640
  // app/logout/page.tsx
@@ -1657,7 +1687,7 @@ export function TokenPanel() {
1657
1687
 
1658
1688
  **Server-managed sessions**:
1659
1689
 
1660
- With `serverSessionUri` configured, tokens are refreshed/revoked by the Server SDK - trigger it by navigating to the catch-all route, then let it redirect back:
1690
+ With `serverSessionUri` configured, tokens are refreshed/revoked by the Server SDK - trigger it by navigating to the catch-all route, then let it redirect back. `sdk.refresh({ returnTo: '/profile' })` (`sdk` from `useStrivacity()`) performs the same refresh navigation for you:
1661
1691
 
1662
1692
  ```tsx
1663
1693
  'use client';
@@ -1702,23 +1732,31 @@ const ctx = useStrivacity<RedirectFlow>();
1702
1732
  ```ts
1703
1733
  {
1704
1734
  // SDK instance (access any SDK method)
1705
- sdk: RedirectFlow | PopupFlow | EmbeddedFlow | NativeFlow;
1735
+ readonly sdk: RedirectFlow | PopupFlow | EmbeddedFlow | NativeFlow;
1706
1736
 
1707
1737
  // Reactive state (plain values - the component re-renders when they change)
1708
- loading: boolean; // True during initialization
1709
- isAuthenticated: boolean; // True if user has valid session
1710
- idTokenClaims: IdTokenClaims | null; // Decoded ID token claims
1711
- accessToken: string | null; // Current access token
1712
- refreshToken: string | null; // Current refresh token
1713
-
1714
- // Methods (all are async)
1715
- login(params?: LoginParams): Promise<void>; // Start login flow
1716
- register(params?: LoginParams): Promise<void>; // Start registration flow
1717
- handleCallback(url?: string): Promise<void>; // Handle OAuth callback
1738
+ readonly loading: boolean; // True during initialization
1739
+ readonly language: string; // Current BCP 47 language code
1740
+ readonly isAuthenticated: boolean; // True if user has valid session
1741
+ readonly idTokenClaims: IdTokenClaims | null; // Decoded ID token claims
1742
+ readonly accessToken: string | null; // Current access token
1743
+ readonly refreshToken: string | null; // Current refresh token
1744
+ readonly accessTokenExpired: boolean; // True once the access token has expired
1745
+ readonly accessTokenExpirationDate: number | null; // Access token expiration timestamp
1746
+
1747
+ // Methods (same signatures as the underlying flow's methods)
1748
+ init(): Promise<void>; // Initialize the SDK (load metadata, restore a persisted session)
1749
+ checkAuthentication(params?: { autoRefresh: boolean }): Promise<boolean>; // Check the session, optionally refreshing the token (never when serverSessionUri is set)
1750
+ login(params?: RedirectParams | PopupParams): Promise<void>; // Start login flow (redirect: `returnTo` sets where handleCallback() sends the user) (embedded/native: returns an EmbeddedLoginFlow/NativeLoginFlow instead)
1751
+ register(params?: RedirectParams | PopupParams): Promise<void>; // Start registration flow (embedded/native: returns an EmbeddedLoginFlow/NativeLoginFlow instead)
1752
+ handleCallback(url?: string | URL): Promise<{ returnTo?: string }>; // Handle OAuth callback; resolves to the `returnTo` given to login()
1718
1753
  logout(params?: LogoutParams): Promise<void>; // End session
1719
- refresh(): Promise<void>; // Refresh access token
1754
+ refresh(params?: { returnTo?: string }): Promise<void>; // Refresh access token (server-managed: navigates to the server's refresh route, `${authUrlPrefix}/refresh`, instead; `returnTo` sets where it returns, default: the current URL)
1720
1755
  revoke(): Promise<void>; // Revoke tokens
1721
- entry(): Promise<EntryData>; // Handle external entry (embedded/native only)
1756
+ tokenExchange(params?: Record<string, string>): Promise<void>; // Perform a token exchange
1757
+ entry(url?: string | URL, params?: RedirectOptions): Promise<void | EntryResponse>; // Handle external entry (resolves to EntryResponse in embedded/native mode)
1758
+ subscribeToEvent<T extends keyof EventFunctions>(eventName: T, callbackFn: (...params: Parameters<EventFunctions[T]>) => Promise<void> | void): { dispose: () => void }; // Subscribe to a single SDK event
1759
+ subscribeToAllEvents(callbackFn: (...params: Array<unknown>) => Promise<void> | void): { dispose: () => void }; // Subscribe to all SDK events
1722
1760
  }
1723
1761
  ```
1724
1762
 
@@ -1744,10 +1782,10 @@ const ctx = useNativeLogin({
1744
1782
  {
1745
1783
  params?: NativeParams; // Initial flow parameters
1746
1784
  onLogin?: (session: SessionData) => void | Promise<void>; // Called on successful login
1747
- onClose?: () => void; // Called when user closes the flow
1748
- onError?: (error: unknown) => void; // Called on error
1749
- onFallback?: (error: FallbackError) => void; // Called when fallback needed
1750
- onGlobalMessage?: (message: NativeFlowMessage) => void; // Called for global messages
1785
+ onClose?: () => void | Promise<void>; // Called when user closes the flow
1786
+ onError?: (error: Error) => void | Promise<void>; // Called on error
1787
+ onFallback?: (error: FallbackError) => void | Promise<void>; // Called when fallback needed
1788
+ onGlobalMessage?: (message: NativeFlowMessage) => void | Promise<void>; // Called for global messages
1751
1789
  }
1752
1790
  ```
1753
1791
 
@@ -1770,9 +1808,19 @@ const ctx = useNativeLogin({
1770
1808
  }
1771
1809
  ```
1772
1810
 
1811
+ #### useNativeLoginContext
1812
+
1813
+ Returns the context of the currently mounted `useNativeLogin()` from any component (e.g. your own widget components), without passing it down as props. Before `useNativeLogin()` has mounted it returns an empty default context (`loading: true`, no-op methods).
1814
+
1815
+ ```ts
1816
+ import { useNativeLoginContext } from '@strivacity/sdk-next/client';
1817
+
1818
+ const { forms, messages, setFormValue, submitForm } = useNativeLoginContext();
1819
+ ```
1820
+
1773
1821
  #### withAuthGuard (client)
1774
1822
 
1775
- Higher-order component that guards a component with authentication. Waits for the SDK to finish loading, checks the session, and redirects to the login page if the user is not authenticated. Not to be confused with the Server SDK's [`withAuthGuard`](#withauthguard), which guards a page/route server-side.
1823
+ Higher-order component that guards a component with authentication. Waits for the SDK to finish loading, checks the session, and redirects to the login page if the user is not authenticated (with the current path as `returnTo`, e.g. `/login?returnTo=%2Forders` - pass it on with `login({ returnTo })`). With server-managed sessions, an expired session is sent through the server's refresh route instead (`sdk.refresh()`, returning to the current URL). Not to be confused with the Server SDK's [`withAuthGuard`](#withauthguard), which guards a page/route server-side.
1776
1824
 
1777
1825
  ```tsx
1778
1826
  'use client';
@@ -1846,7 +1894,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
1846
1894
 
1847
1895
  ### Accessing the session server-side
1848
1896
 
1849
- Call `getSession()` from any Server Component, Route Handler, or `getServerSideProps` to read the current session without going through the client SDK:
1897
+ Call `getSession()` from any Server Component, Route Handler, or `getServerSideProps` (pass the request there: `sdk.getSession(ctx.req)`) to read the current session without going through the client SDK. In Server Components (no request) and for Pages Router requests it reads the stored session without refreshing, so the returned session can be expired: a rotated session could not be saved there. Use [`withAuthGuard`](#withauthguard), which sends an expiring session through `/auth/refresh`, or check `expires_at` yourself:
1850
1898
 
1851
1899
  ```tsx
1852
1900
  // app/profile/page.tsx (Server Component)
@@ -1864,10 +1912,25 @@ export default async function ProfilePage() {
1864
1912
  }
1865
1913
  ```
1866
1914
 
1915
+ With an App Router request - in Route Handlers, where cookies can be written - `getSession(req)` also refreshes: with `autoRefresh` (the default) it refreshes an expired (or within `refreshSkew`) session first when a refresh token exists, at most once per request (concurrent and later calls with the same `req` share the result), and resolves to `null` if the refresh fails.
1916
+
1917
+ ```ts
1918
+ // app/api/me/route.ts
1919
+ import type { NextRequest } from 'next/server';
1920
+ import { sdk } from '../../../lib/auth/server';
1921
+
1922
+ export async function GET(req: NextRequest) {
1923
+ const session = await sdk.getSession(req);
1924
+ return session ? Response.json({ claims: session.claims }) : Response.json({ error: 'not_authenticated' }, { status: 401 });
1925
+ }
1926
+ ```
1927
+
1867
1928
  ### withAuthGuard
1868
1929
 
1869
1930
  Guards a page and injects a `session` prop, redirecting to `options.loginUri` (default `/login`) when there's no active session.
1870
1931
 
1932
+ The guard also checks expiry. When the access token has expired (or is within `refreshSkew` seconds of expiry) and the session has a refresh token, it redirects to `${authUrlPrefix}/refresh?returnTo=...` - the refresh route writes the rotated session cookie and redirects back. The `returnTo` is the guard's `returnTo` option, falling back to `postLoginRedirectUri` (App Router) or the requested page, `ctx.resolvedUrl` (Pages Router). An expired session without a refresh token - or any expired session with `autoRefresh: false` - is treated as no session and redirects to the login page.
1933
+
1871
1934
  **App Router:**
1872
1935
 
1873
1936
  ```tsx
@@ -1893,7 +1956,7 @@ export default function ProfilePage({ session }: { session: SessionData }) {
1893
1956
  }
1894
1957
  ```
1895
1958
 
1896
- Pass `returnTo` to redirect back to a specific page after login, or (Pages Router only) `getServerSideProps` to run your own data fetching alongside the guard:
1959
+ Pass `returnTo` to redirect back to a specific page after login or refresh, or (Pages Router only) `getServerSideProps` to run your own data fetching alongside the guard:
1897
1960
 
1898
1961
  ```ts
1899
1962
  export const getServerSideProps = sdk.withAuthGuard({
@@ -1938,7 +2001,7 @@ By default the Server SDK stores tokens encrypted in http-only cookies and login
1938
2001
  #### Built-in session storages
1939
2002
 
1940
2003
  - **`createEncryptedCookieStorage(secret, options?)`** - default storage that keeps the session encrypted in an http-only cookie.
1941
- - **`createSessionIdCookieStorage(storage, options?)`** - puts only a small, random session-id cookie on the client and keeps the actual session payload in the `storage` you provide. This supports back-channel logout out of the box.
2004
+ - **`createSessionIdCookieStorage(storage, options?)`** - puts only a small, random session-id cookie on the client and keeps the actual session payload in the `storage` you provide. It supports back-channel logout when `storage` implements `deleteByLogoutToken`.
1942
2005
 
1943
2006
  ```ts
1944
2007
  // lib/auth/storage.ts
@@ -1967,37 +2030,40 @@ export const sdk = createServerSDK({
1967
2030
 
1968
2031
  #### Custom storage
1969
2032
 
1970
- For example you can use Redis via [unstorage](https://npmjs.com/package/unstorage):
2033
+ For example you can use Redis via [unstorage](https://npmjs.com/package/unstorage).
2034
+
2035
+ The SDK always reads and writes the session under the same key (`storageTokenName`), and passes the current request as the last argument. A storage that ignores the request would therefore share a single session across all users, so key the data per browser session instead. The easiest way is to wrap your key-value store with `createSessionIdCookieStorage`, which puts a random session id in a cookie and calls your store with that id as the key:
1971
2036
 
1972
2037
  ```ts
1973
2038
  // lib/auth/storage.ts
1974
2039
  import { createStorage } from 'unstorage';
1975
2040
  import redisDriver from 'unstorage/drivers/redis';
1976
- import type { NextServerStorage, SDKStorage } from '@strivacity/sdk-next/server';
2041
+ import type { ServerStorage, SDKStorage } from '@strivacity/sdk-next/server';
1977
2042
 
1978
2043
  const unstorageInstance = createStorage({ driver: redisDriver({ url: process.env.REDIS_URL }) });
1979
2044
 
1980
- // Custom session storage for tokens
1981
- export const sessionStorage: NextServerStorage = {
2045
+ // Session payload store - `key` is the per-browser session id provided by `createSessionIdCookieStorage`
2046
+ // (raw get/set keep the serialized session string as-is)
2047
+ export const sessionStore: ServerStorage = {
1982
2048
  async get(key) {
1983
- return unstorageInstance.getItem<string>(key);
2049
+ return unstorageInstance.getItemRaw<string>(`session:${key}`);
1984
2050
  },
1985
2051
  async set(key, value) {
1986
- await unstorageInstance.setItem(key, value);
2052
+ await unstorageInstance.setItemRaw(`session:${key}`, value);
1987
2053
  },
1988
2054
  async delete(key) {
1989
- await unstorageInstance.removeItem(key);
2055
+ await unstorageInstance.removeItem(`session:${key}`);
1990
2056
  },
1991
2057
  // Required for back-channel logout support - see below.
1992
- // Scans all stored sessions and removes those matching the logout token's sid or sub claim.
2058
+ // Scans all stored sessions and removes those whose ID token claims match the logout token's sid or sub claim.
1993
2059
  async deleteByLogoutToken(logoutToken) {
1994
- const keys = await unstorageInstance.getKeys();
2060
+ const keys = await unstorageInstance.getKeys('session');
1995
2061
  await Promise.all(
1996
2062
  keys.map(async (key) => {
1997
- const raw = await unstorageInstance.getItem<string>(key);
2063
+ const raw = await unstorageInstance.getItemRaw<string>(key);
1998
2064
  if (!raw) return;
1999
2065
  const session = JSON.parse(raw);
2000
- if ((logoutToken.sid && session.sid === logoutToken.sid) || (logoutToken.sub && session.sub === logoutToken.sub)) {
2066
+ if ((logoutToken.sid && session.claims?.sid === logoutToken.sid) || (logoutToken.sub && session.claims?.sub === logoutToken.sub)) {
2001
2067
  await unstorageInstance.removeItem(key);
2002
2068
  }
2003
2069
  }),
@@ -2021,13 +2087,13 @@ export const stateStorage: SDKStorage = {
2021
2087
 
2022
2088
  ```ts
2023
2089
  // lib/auth/server.ts
2024
- import { createServerSDK } from '@strivacity/sdk-next/server';
2090
+ import { createServerSDK, createSessionIdCookieStorage } from '@strivacity/sdk-next/server';
2025
2091
  import { sdkOptions } from './options';
2026
- import { sessionStorage, stateStorage } from './storage';
2092
+ import { sessionStore, stateStorage } from './storage';
2027
2093
 
2028
2094
  export const sdk = createServerSDK({
2029
2095
  ...sdkOptions,
2030
- storage: sessionStorage, // Custom Redis-backed session storage
2096
+ storage: createSessionIdCookieStorage(sessionStore), // Custom Redis-backed session storage, keyed by a session-id cookie
2031
2097
  stateStorage, // Custom Redis-backed state storage
2032
2098
  });
2033
2099
  ```
@@ -2038,9 +2104,9 @@ export const sdk = createServerSDK({
2038
2104
 
2039
2105
  OIDC back-channel logout lets the authorization server terminate sessions server-to-server, without involving the browser. When the IDP sends a logout event (e.g. an admin terminates a session, or the user logs out from a different device), it POSTs a signed `logout_token` JWT to `/auth/backchannel-logout` - already wired up by the catch-all route from [Setup](#setup) - which routes it to `sdk.handleBackChannelLogout(req)`.
2040
2106
 
2041
- The handler verifies the token's signature against the IDP's JWKS, validates the `iss`, `aud`, `iat` (freshness), and `jti` (replay protection) claims, requires the `http://schemas.openid.net/event/backchannel-logout` event and a `sid` or `sub` claim, then calls `storage.deleteByLogoutToken({ sid?, sub? })` to remove the matching session(s). It responds `200` on success, `400` for an invalid or malformed `logout_token`, and `501` if the configured storage doesn't implement `deleteByLogoutToken`.
2107
+ The handler verifies the token's signature against the IDP's JWKS, validates the `iss`, `aud`, `iat` (freshness), and `jti` (replay protection) claims, requires the `http://schemas.openid.net/event/backchannel-logout` event and a `sid` or `sub` claim, then calls `storage.deleteByLogoutToken({ sid?, sub? })` to remove the matching session(s). It responds `200` on success, `400` for an invalid or malformed `logout_token`, `501` if the configured storage doesn't implement `deleteByLogoutToken`, and `500` if deleting the session fails.
2042
2108
 
2043
- > **The default encrypted-cookie storage does not support back-channel logout** because each cookie is bound to a single browser session - there is no server-side index to look up by `sid` or `sub`. To support back-channel logout, use [`createSessionIdCookieStorage`](#server-storages) with a `storage` that implements `deleteByLogoutToken` (e.g. `createServerMemoryStorage()` for local testing), or a fully custom server storage as shown in the [Custom storage](#server-storages) example above.
2109
+ > **The default encrypted-cookie storage does not support back-channel logout** because each cookie is bound to a single browser session - there is no server-side index to look up by `sid` or `sub`. To support back-channel logout, use [`createSessionIdCookieStorage`](#server-storages) with a `storage` that implements `deleteByLogoutToken`, e.g. `createServerMemoryStorage()` for local testing or the Redis-backed store from the [Custom storage](#server-storages) example above.
2044
2110
 
2045
2111
  Configure the **Back-channel logout URI** in your Strivacity application settings to:
2046
2112
 
@@ -2057,7 +2123,7 @@ For a complete explanation of the handshake and validation performed, see the co
2057
2123
  options: ServerSDKOptions; // resolved server SDK configuration
2058
2124
 
2059
2125
  // Session management
2060
- getSession(req?): Promise<SessionData | null>; // read the current session
2126
+ getSession(req?): Promise<SessionData | null>; // read the current session; with an App Router request and `autoRefresh` (default) it refreshes an expired one first (once per request, null if the refresh fails). Without a request (Server Components) or with a Pages Router request it never refreshes
2061
2127
  updateSession(session, req?): Promise<void>; // persist new session data
2062
2128
  refreshSession(req?): Promise<SessionData>; // refresh tokens using the refresh token
2063
2129
  revokeSession(req?): Promise<void>; // revoke tokens and clear the session
@@ -2093,8 +2159,8 @@ The Server SDK accepts the same configuration as the client SDK (see [Configurat
2093
2159
  | `stateStorage` | `SDKStorage` | No | In-memory `Map` | Custom OAuth2 state storage |
2094
2160
  | `authUrlPrefix` | `string` | No | `'/auth'` | URL prefix matched by `handler`/the catch-all route |
2095
2161
  | `loginUri` | `string` | No | `'/login'` | Page `withAuthGuard` redirects to when there's no session |
2096
- | `postLoginRedirectUri` | `string` | No | - | Default redirect after login when no `?returnTo=` is given |
2097
- | `postLogoutRedirectUri` | `string` | No | - | Default redirect after logout |
2162
+ | `postLoginRedirectUri` | `string` | No | origin of `redirectUri` | Default redirect after login when no `?returnTo=` is given |
2163
+ | `postLogoutRedirectUri` | `string` | No | origin of `redirectUri` | Default redirect after logout |
2098
2164
  | `cookieMaxAge` | `number` | No | `2592000` (30 days) | Max age of the session cookie in seconds |
2099
2165
 
2100
2166
  ---
@@ -2130,7 +2196,7 @@ The client SDK accepts the same configuration as the core SDK - see the [core SD
2130
2196
 
2131
2197
  ### Migrating to v4.0
2132
2198
 
2133
- v4 replaces the SDK's class-based flow architecture with function-based architecture, and adds a first-class Server SDK for server-managed (BFF) sessions. `StyAuthProvider`, `useStrivacity()`, `useNativeLogin()`, and the built-in `redirect`/`popup`/`embedded`/`native` modes are unchanged - only apps that used `mode: 'custom'` or drove `native` mode through the old `NativeFlowHandler` need to update their code.
2199
+ v4 replaces the SDK's class-based flow architecture with function-based architecture, and adds a first-class Server SDK for server-managed (BFF) sessions. `StyAuthProvider`, `useStrivacity()`, and the built-in `redirect`/`popup`/`embedded`/`native` modes are unchanged (`useStrivacity()` no longer exposes `options` - use `sdk.options`). `useNativeLogin()` is new in v4: it replaces v3's `<StyLoginRenderer>` component (and `NativeFlowContext`), so `native` mode now renders your own widget components driven by [`useNativeLogin()`](#usenativelogin) and [`useNativeLoginContext()`](#usenativelogincontext). Apps that rendered `<StyLoginRenderer>`, used `mode: 'custom'`, or drove `native` mode through the old `NativeFlowHandler` need to update their code.
2134
2200
 
2135
2201
  #### Class-based flows replaced by functions
2136
2202
 
@@ -2157,7 +2223,7 @@ import type { SDKInitConfig, SDKOptions } from '@strivacity/sdk-core/types';
2157
2223
 
2158
2224
  export function createCustomFlow(initConfig: SDKInitConfig) {
2159
2225
  const state = getDefaultFlowState();
2160
- const options = getSDKOptions<SDKOptions>(state, initConfig);
2226
+ const options = getSDKOptions<SDKOptions>(initConfig);
2161
2227
  const base = createBaseFlow(state, options);
2162
2228
 
2163
2229
  async function refresh(): Promise<void> {
@@ -1,2 +1,2 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../utils.cjs");let t=require("next/server");var n=n=>r=>async(i,a)=>{let o=i instanceof Request?e.toNextRequest(i):i;if(!await n.getSession(o))return t.NextResponse.json({error:`not_authenticated`,description:`The user does not have an active session or is not authenticated`},{status:401});let s=await r(o,a);return s instanceof t.NextResponse?s:new t.NextResponse(s.body,s)},r=e=>t=>async(n,r)=>{if(!await e.getSession(n))return r.status(401).json({error:`not_authenticated`,description:`The user does not have an active session or is not authenticated`});await t(n,r)};exports.apiAppRouteHandlerFactory=n,exports.apiPageRouteHandlerFactory=r;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../utils.cjs");let t=require("next/server");var n=n=>r=>async(i,a)=>{let o=i instanceof Request?e.toNextRequest(i):i;if(!await n.getSession(o))return t.NextResponse.json({error:`not_authenticated`,description:`The user does not have an active session or is not authenticated`},{status:401});let s=await r(o,a);return s instanceof t.NextResponse?s:new t.NextResponse(s.body,s)},r=e=>t=>async(n,r)=>{if(!await e.getSession(n,{autoRefresh:!1}))return r.status(401).json({error:`not_authenticated`,description:`The user does not have an active session or is not authenticated`});await t(n,r)};exports.apiAppRouteHandlerFactory=n,exports.apiPageRouteHandlerFactory=r;
2
2
  //# sourceMappingURL=api.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"api.cjs","names":[],"sources":["../../../src/server/handlers/api.ts"],"sourcesContent":["import type { BaseServerSDK, PagesRouterRequest, WithApiAuthRequiredAppRoute, WithApiAuthRequiredPageRoute } from '../types';\nimport { NextRequest, NextResponse } from 'next/server';\nimport { toNextRequest } from '../utils';\n\nexport const apiAppRouteHandlerFactory =\n\t(sdk: BaseServerSDK<NextRequest | Request | PagesRouterRequest | undefined>): WithApiAuthRequiredAppRoute =>\n\t(apiRoute) =>\n\tasync (req: NextRequest | Request, params): Promise<NextResponse> => {\n\t\tconst nextReq = req instanceof Request ? toNextRequest(req) : req;\n\n\t\tconst session = await sdk.getSession(nextReq);\n\n\t\tif (!session) {\n\t\t\treturn NextResponse.json(\n\t\t\t\t{\n\t\t\t\t\terror: 'not_authenticated',\n\t\t\t\t\tdescription: 'The user does not have an active session or is not authenticated',\n\t\t\t\t},\n\t\t\t\t{ status: 401 },\n\t\t\t);\n\t\t}\n\n\t\tconst apiRes: NextResponse | Response = await apiRoute(nextReq, params);\n\t\tconst nextApiRes: NextResponse = apiRes instanceof NextResponse ? apiRes : new NextResponse(apiRes.body, apiRes);\n\n\t\treturn nextApiRes;\n\t};\n\nexport const apiPageRouteHandlerFactory =\n\t(sdk: BaseServerSDK<NextRequest | Request | PagesRouterRequest | undefined>): WithApiAuthRequiredPageRoute =>\n\t(apiRoute) =>\n\tasync (req, res) => {\n\t\tconst session = await sdk.getSession(req);\n\n\t\tif (!session) {\n\t\t\treturn res.status(401).json({\n\t\t\t\terror: 'not_authenticated',\n\t\t\t\tdescription: 'The user does not have an active session or is not authenticated',\n\t\t\t});\n\t\t}\n\n\t\tawait apiRoute(req, res);\n\t};\n"],"mappings":"gIAIA,IAAa,EACX,GACA,GACD,MAAO,EAA4B,IAAkC,CACpE,IAAM,EAAU,aAAe,QAAU,EAAA,cAAc,CAAG,EAAI,EAI9D,GAAI,CAAC,MAFiB,EAAI,WAAW,CAAO,EAG3C,OAAO,EAAA,aAAa,KACnB,CACC,MAAO,oBACP,YAAa,kEACd,EACA,CAAE,OAAQ,GAAI,CACf,EAGD,IAAM,EAAkC,MAAM,EAAS,EAAS,CAAM,EAGtE,OAFiC,aAAkB,EAAA,aAAe,EAAS,IAAI,EAAA,aAAa,EAAO,KAAM,CAAM,CAGhH,EAEY,EACX,GACA,GACD,MAAO,EAAK,IAAQ,CAGnB,GAAI,CAAC,MAFiB,EAAI,WAAW,CAAG,EAGvC,OAAO,EAAI,OAAO,GAAG,CAAC,CAAC,KAAK,CAC3B,MAAO,oBACP,YAAa,kEACd,CAAC,EAGF,MAAM,EAAS,EAAK,CAAG,CACxB"}
1
+ {"version":3,"file":"api.cjs","names":[],"sources":["../../../src/server/handlers/api.ts"],"sourcesContent":["import type { BaseServerSDK, PagesRouterRequest, WithApiAuthRequiredAppRoute, WithApiAuthRequiredPageRoute } from '../types';\nimport { NextRequest, NextResponse } from 'next/server';\nimport { toNextRequest } from '../utils';\n\nexport const apiAppRouteHandlerFactory =\n\t(sdk: BaseServerSDK<NextRequest | Request | PagesRouterRequest | undefined>): WithApiAuthRequiredAppRoute =>\n\t(apiRoute) =>\n\tasync (req: NextRequest | Request, params): Promise<NextResponse> => {\n\t\tconst nextReq = req instanceof Request ? toNextRequest(req) : req;\n\n\t\tconst session = await sdk.getSession(nextReq);\n\n\t\tif (!session) {\n\t\t\treturn NextResponse.json(\n\t\t\t\t{\n\t\t\t\t\terror: 'not_authenticated',\n\t\t\t\t\tdescription: 'The user does not have an active session or is not authenticated',\n\t\t\t\t},\n\t\t\t\t{ status: 401 },\n\t\t\t);\n\t\t}\n\n\t\tconst apiRes: NextResponse | Response = await apiRoute(nextReq, params);\n\t\tconst nextApiRes: NextResponse = apiRes instanceof NextResponse ? apiRes : new NextResponse(apiRes.body, apiRes);\n\n\t\treturn nextApiRes;\n\t};\n\nexport const apiPageRouteHandlerFactory =\n\t(sdk: BaseServerSDK<NextRequest | Request | PagesRouterRequest | undefined>): WithApiAuthRequiredPageRoute =>\n\t(apiRoute) =>\n\tasync (req, res) => {\n\t\t// NOTE: Pages Router: no cookies() store to save a refreshed session in, so read it as stored\n\t\tconst session = await sdk.getSession(req, { autoRefresh: false });\n\n\t\tif (!session) {\n\t\t\treturn res.status(401).json({\n\t\t\t\terror: 'not_authenticated',\n\t\t\t\tdescription: 'The user does not have an active session or is not authenticated',\n\t\t\t});\n\t\t}\n\n\t\tawait apiRoute(req, res);\n\t};\n"],"mappings":"gIAIA,IAAa,EACX,GACA,GACD,MAAO,EAA4B,IAAkC,CACpE,IAAM,EAAU,aAAe,QAAU,EAAA,cAAc,CAAG,EAAI,EAI9D,GAAI,CAAC,MAFiB,EAAI,WAAW,CAAO,EAG3C,OAAO,EAAA,aAAa,KACnB,CACC,MAAO,oBACP,YAAa,kEACd,EACA,CAAE,OAAQ,GAAI,CACf,EAGD,IAAM,EAAkC,MAAM,EAAS,EAAS,CAAM,EAGtE,OAFiC,aAAkB,EAAA,aAAe,EAAS,IAAI,EAAA,aAAa,EAAO,KAAM,CAAM,CAGhH,EAEY,EACX,GACA,GACD,MAAO,EAAK,IAAQ,CAInB,GAAI,CAAC,MAFiB,EAAI,WAAW,EAAK,CAAE,YAAa,EAAM,CAAC,EAG/D,OAAO,EAAI,OAAO,GAAG,CAAC,CAAC,KAAK,CAC3B,MAAO,oBACP,YAAa,kEACd,CAAC,EAGF,MAAM,EAAS,EAAK,CAAG,CACxB"}
@@ -1,2 +1,2 @@
1
- import{toNextRequest as e}from"../utils.mjs";import{NextResponse as t}from"next/server";var n=n=>r=>async(i,a)=>{let o=i instanceof Request?e(i):i;if(!await n.getSession(o))return t.json({error:`not_authenticated`,description:`The user does not have an active session or is not authenticated`},{status:401});let s=await r(o,a);return s instanceof t?s:new t(s.body,s)},r=e=>t=>async(n,r)=>{if(!await e.getSession(n))return r.status(401).json({error:`not_authenticated`,description:`The user does not have an active session or is not authenticated`});await t(n,r)};export{n as apiAppRouteHandlerFactory,r as apiPageRouteHandlerFactory};
1
+ import{toNextRequest as e}from"../utils.mjs";import{NextResponse as t}from"next/server";var n=n=>r=>async(i,a)=>{let o=i instanceof Request?e(i):i;if(!await n.getSession(o))return t.json({error:`not_authenticated`,description:`The user does not have an active session or is not authenticated`},{status:401});let s=await r(o,a);return s instanceof t?s:new t(s.body,s)},r=e=>t=>async(n,r)=>{if(!await e.getSession(n,{autoRefresh:!1}))return r.status(401).json({error:`not_authenticated`,description:`The user does not have an active session or is not authenticated`});await t(n,r)};export{n as apiAppRouteHandlerFactory,r as apiPageRouteHandlerFactory};
2
2
  //# sourceMappingURL=api.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"api.mjs","names":[],"sources":["../../../src/server/handlers/api.ts"],"sourcesContent":["import type { BaseServerSDK, PagesRouterRequest, WithApiAuthRequiredAppRoute, WithApiAuthRequiredPageRoute } from '../types';\nimport { NextRequest, NextResponse } from 'next/server';\nimport { toNextRequest } from '../utils';\n\nexport const apiAppRouteHandlerFactory =\n\t(sdk: BaseServerSDK<NextRequest | Request | PagesRouterRequest | undefined>): WithApiAuthRequiredAppRoute =>\n\t(apiRoute) =>\n\tasync (req: NextRequest | Request, params): Promise<NextResponse> => {\n\t\tconst nextReq = req instanceof Request ? toNextRequest(req) : req;\n\n\t\tconst session = await sdk.getSession(nextReq);\n\n\t\tif (!session) {\n\t\t\treturn NextResponse.json(\n\t\t\t\t{\n\t\t\t\t\terror: 'not_authenticated',\n\t\t\t\t\tdescription: 'The user does not have an active session or is not authenticated',\n\t\t\t\t},\n\t\t\t\t{ status: 401 },\n\t\t\t);\n\t\t}\n\n\t\tconst apiRes: NextResponse | Response = await apiRoute(nextReq, params);\n\t\tconst nextApiRes: NextResponse = apiRes instanceof NextResponse ? apiRes : new NextResponse(apiRes.body, apiRes);\n\n\t\treturn nextApiRes;\n\t};\n\nexport const apiPageRouteHandlerFactory =\n\t(sdk: BaseServerSDK<NextRequest | Request | PagesRouterRequest | undefined>): WithApiAuthRequiredPageRoute =>\n\t(apiRoute) =>\n\tasync (req, res) => {\n\t\tconst session = await sdk.getSession(req);\n\n\t\tif (!session) {\n\t\t\treturn res.status(401).json({\n\t\t\t\terror: 'not_authenticated',\n\t\t\t\tdescription: 'The user does not have an active session or is not authenticated',\n\t\t\t});\n\t\t}\n\n\t\tawait apiRoute(req, res);\n\t};\n"],"mappings":"wFAIA,IAAa,EACX,GACA,GACD,MAAO,EAA4B,IAAkC,CACpE,IAAM,EAAU,aAAe,QAAU,EAAc,CAAG,EAAI,EAI9D,GAAI,CAAC,MAFiB,EAAI,WAAW,CAAO,EAG3C,OAAO,EAAa,KACnB,CACC,MAAO,oBACP,YAAa,kEACd,EACA,CAAE,OAAQ,GAAI,CACf,EAGD,IAAM,EAAkC,MAAM,EAAS,EAAS,CAAM,EAGtE,OAFiC,aAAkB,EAAe,EAAS,IAAI,EAAa,EAAO,KAAM,CAAM,CAGhH,EAEY,EACX,GACA,GACD,MAAO,EAAK,IAAQ,CAGnB,GAAI,CAAC,MAFiB,EAAI,WAAW,CAAG,EAGvC,OAAO,EAAI,OAAO,GAAG,CAAC,CAAC,KAAK,CAC3B,MAAO,oBACP,YAAa,kEACd,CAAC,EAGF,MAAM,EAAS,EAAK,CAAG,CACxB"}
1
+ {"version":3,"file":"api.mjs","names":[],"sources":["../../../src/server/handlers/api.ts"],"sourcesContent":["import type { BaseServerSDK, PagesRouterRequest, WithApiAuthRequiredAppRoute, WithApiAuthRequiredPageRoute } from '../types';\nimport { NextRequest, NextResponse } from 'next/server';\nimport { toNextRequest } from '../utils';\n\nexport const apiAppRouteHandlerFactory =\n\t(sdk: BaseServerSDK<NextRequest | Request | PagesRouterRequest | undefined>): WithApiAuthRequiredAppRoute =>\n\t(apiRoute) =>\n\tasync (req: NextRequest | Request, params): Promise<NextResponse> => {\n\t\tconst nextReq = req instanceof Request ? toNextRequest(req) : req;\n\n\t\tconst session = await sdk.getSession(nextReq);\n\n\t\tif (!session) {\n\t\t\treturn NextResponse.json(\n\t\t\t\t{\n\t\t\t\t\terror: 'not_authenticated',\n\t\t\t\t\tdescription: 'The user does not have an active session or is not authenticated',\n\t\t\t\t},\n\t\t\t\t{ status: 401 },\n\t\t\t);\n\t\t}\n\n\t\tconst apiRes: NextResponse | Response = await apiRoute(nextReq, params);\n\t\tconst nextApiRes: NextResponse = apiRes instanceof NextResponse ? apiRes : new NextResponse(apiRes.body, apiRes);\n\n\t\treturn nextApiRes;\n\t};\n\nexport const apiPageRouteHandlerFactory =\n\t(sdk: BaseServerSDK<NextRequest | Request | PagesRouterRequest | undefined>): WithApiAuthRequiredPageRoute =>\n\t(apiRoute) =>\n\tasync (req, res) => {\n\t\t// NOTE: Pages Router: no cookies() store to save a refreshed session in, so read it as stored\n\t\tconst session = await sdk.getSession(req, { autoRefresh: false });\n\n\t\tif (!session) {\n\t\t\treturn res.status(401).json({\n\t\t\t\terror: 'not_authenticated',\n\t\t\t\tdescription: 'The user does not have an active session or is not authenticated',\n\t\t\t});\n\t\t}\n\n\t\tawait apiRoute(req, res);\n\t};\n"],"mappings":"wFAIA,IAAa,EACX,GACA,GACD,MAAO,EAA4B,IAAkC,CACpE,IAAM,EAAU,aAAe,QAAU,EAAc,CAAG,EAAI,EAI9D,GAAI,CAAC,MAFiB,EAAI,WAAW,CAAO,EAG3C,OAAO,EAAa,KACnB,CACC,MAAO,oBACP,YAAa,kEACd,EACA,CAAE,OAAQ,GAAI,CACf,EAGD,IAAM,EAAkC,MAAM,EAAS,EAAS,CAAM,EAGtE,OAFiC,aAAkB,EAAe,EAAS,IAAI,EAAa,EAAO,KAAM,CAAM,CAGhH,EAEY,EACX,GACA,GACD,MAAO,EAAK,IAAQ,CAInB,GAAI,CAAC,MAFiB,EAAI,WAAW,EAAK,CAAE,YAAa,EAAM,CAAC,EAG/D,OAAO,EAAI,OAAO,GAAG,CAAC,CAAC,KAAK,CAC3B,MAAO,oBACP,YAAa,kEACd,CAAC,EAGF,MAAM,EAAS,EAAK,CAAG,CACxB"}
@@ -1,2 +1,2 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=function(e,t,n){let r=Promise.resolve();function i(e){let t=new Event(`vite:preloadError`,{cancelable:!0});if(t.payload=e,window.dispatchEvent(t),!t.defaultPrevented)throw e}return r.then(t=>{for(let e of t||[])e.status===`rejected`&&i(e.reason);return e().catch(i)})},t=t=>(n,r={})=>async i=>{let a=await t.getSession();if(!a){let n=typeof r.returnTo==`function`?await r.returnTo(i):r.returnTo,{redirect:a}=await e(async()=>{let{redirect:e}=await import(`next/navigation`);return{redirect:e}},void 0);a(`${t.options.loginUri}${n?`?returnTo=${encodeURIComponent(n)}`:``}`)}return n({...i,session:a})},n=e=>({getServerSideProps:t,returnTo:n}={})=>async r=>{let i=await e.getSession();if(!i)return{redirect:{destination:`${e.options.loginUri}?returnTo=${encodeURIComponent(n||r.resolvedUrl)}`,permanent:!1}};let a={props:{}};if(t&&(a=await t(r)),a.props instanceof Promise){let e=await a.props;return{...a,props:{session:i,...e}}}return{...a,props:{session:i,...a.props}}};exports.appRouteHandlerFactory=t,exports.pageRouteHandlerFactory=n;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require("@strivacity/sdk-core/utils");var t=function(e,t,n){let r=Promise.resolve();function i(e){let t=new Event(`vite:preloadError`,{cancelable:!0});if(t.payload=e,window.dispatchEvent(t),!t.defaultPrevented)throw e}return r.then(t=>{for(let e of t||[])e.status===`rejected`&&i(e.reason);return e().catch(i)})};function n(e,t){return`${e.options.authUrlPrefix}/refresh?returnTo=${encodeURIComponent(t)}`}var r=r=>(i,a={})=>async o=>{let s=await r.getSession(void 0,{autoRefresh:!1});if(s&&(0,e.isSessionExpired)(s,r.options.refreshSkew)){if(s.refresh_token&&r.options.autoRefresh!==!1){let e=typeof a.returnTo==`function`?await a.returnTo(o):a.returnTo,{redirect:i}=await t(async()=>{let{redirect:e}=await import(`next/navigation`);return{redirect:e}},void 0);i(n(r,e||r.options.postLoginRedirectUri))}s=null}if(!s){let e=typeof a.returnTo==`function`?await a.returnTo(o):a.returnTo,{redirect:n}=await t(async()=>{let{redirect:e}=await import(`next/navigation`);return{redirect:e}},void 0);n(`${r.options.loginUri}${e?`?returnTo=${encodeURIComponent(e)}`:``}`)}return i({...o,session:s})},i=t=>({getServerSideProps:r,returnTo:i}={})=>async a=>{let o=await t.getSession(a.req,{autoRefresh:!1});if(o&&(0,e.isSessionExpired)(o,t.options.refreshSkew))return{redirect:{destination:o.refresh_token&&t.options.autoRefresh!==!1?n(t,i||a.resolvedUrl):`${t.options.loginUri}?returnTo=${encodeURIComponent(i||a.resolvedUrl)}`,permanent:!1}};if(!o)return{redirect:{destination:`${t.options.loginUri}?returnTo=${encodeURIComponent(i||a.resolvedUrl)}`,permanent:!1}};let s={props:{}};if(r&&(s=await r(a)),s.props instanceof Promise){let e=await s.props;return{...s,props:{session:o,...e}}}return{...s,props:{session:o,...s.props}}};exports.appRouteHandlerFactory=r,exports.pageRouteHandlerFactory=i;
2
2
  //# sourceMappingURL=route.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"route.cjs","names":[],"sources":["../../../src/server/handlers/route.ts"],"sourcesContent":["import type { NextRequest } from 'next/server';\nimport type {\n\tAppRouterPageRoute,\n\tAppRouterPageRouteOpts,\n\tBaseServerSDK,\n\tPagesRouterRequest,\n\tWithAuthGuardAppRouter,\n\tWithAuthGuardAppRouterOptions,\n\tWithAuthGuardPageRouter,\n} from '../types';\n\nexport const appRouteHandlerFactory =\n\t(sdk: BaseServerSDK<NextRequest | Request | PagesRouterRequest | undefined>): WithAuthGuardAppRouter =>\n\t<P extends AppRouterPageRouteOpts = AppRouterPageRouteOpts>(handler: AppRouterPageRoute<P>, opts: WithAuthGuardAppRouterOptions<P> = {}) =>\n\tasync (params: P) => {\n\t\tconst session = await sdk.getSession();\n\n\t\tif (!session) {\n\t\t\tconst returnTo = typeof opts.returnTo === 'function' ? await opts.returnTo(params) : opts.returnTo;\n\t\t\tconst { redirect } = await import('next/navigation');\n\n\t\t\tredirect(`${sdk.options.loginUri}${returnTo ? `?returnTo=${encodeURIComponent(returnTo)}` : ''}`);\n\t\t}\n\n\t\treturn handler({ ...params, session });\n\t};\n\nexport const pageRouteHandlerFactory =\n\t(sdk: BaseServerSDK<NextRequest | Request | PagesRouterRequest | undefined>): WithAuthGuardPageRouter =>\n\t({ getServerSideProps, returnTo } = {}) =>\n\tasync (ctx) => {\n\t\tconst session = await sdk.getSession();\n\n\t\tif (!session) {\n\t\t\treturn {\n\t\t\t\tredirect: {\n\t\t\t\t\tdestination: `${sdk.options.loginUri}?returnTo=${encodeURIComponent(returnTo || ctx.resolvedUrl)}`,\n\t\t\t\t\tpermanent: false,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\t\tlet ret: any = { props: {} };\n\n\t\tif (getServerSideProps) {\n\t\t\tret = await getServerSideProps(ctx);\n\t\t}\n\n\t\tif (ret.props instanceof Promise) {\n\t\t\tconst props = await ret.props;\n\n\t\t\treturn {\n\t\t\t\t...ret,\n\t\t\t\tprops: {\n\t\t\t\t\tsession,\n\t\t\t\t\t...props,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\treturn { ...ret, props: { session, ...ret.props } };\n\t};\n"],"mappings":"sVAWa,EACX,IAC2D,EAAgC,EAAyC,CAAC,IACtI,KAAO,IAAc,CACpB,IAAM,EAAU,MAAM,EAAI,WAAW,EAErC,GAAI,CAAC,EAAS,CACb,IAAM,EAAW,OAAO,EAAK,UAAa,WAAa,MAAM,EAAK,SAAS,CAAM,EAAI,EAAK,SACpF,CAAE,YAAA,MAAA,EAAA,SAAA,CAAF,GAAA,CAAE,YAAa,MAAM,OAAO,+CAElC,EAAS,GAAG,EAAI,QAAQ,WAAW,EAAW,aAAa,mBAAmB,CAAQ,IAAM,IAAI,CACjG,CAEA,OAAO,EAAQ,CAAE,GAAG,EAAQ,SAAQ,CAAC,CACtC,EAEY,EACX,IACA,CAAE,qBAAoB,YAAa,CAAC,IACrC,KAAO,IAAQ,CACd,IAAM,EAAU,MAAM,EAAI,WAAW,EAErC,GAAI,CAAC,EACJ,MAAO,CACN,SAAU,CACT,YAAa,GAAG,EAAI,QAAQ,SAAS,YAAY,mBAAmB,GAAY,EAAI,WAAW,IAC/F,UAAW,EACZ,CACD,EAID,IAAI,EAAW,CAAE,MAAO,CAAC,CAAE,EAM3B,GAJI,IACH,EAAM,MAAM,EAAmB,CAAG,GAG/B,EAAI,iBAAiB,QAAS,CACjC,IAAM,EAAQ,MAAM,EAAI,MAExB,MAAO,CACN,GAAG,EACH,MAAO,CACN,UACA,GAAG,CACJ,CACD,CACD,CAEA,MAAO,CAAE,GAAG,EAAK,MAAO,CAAE,UAAS,GAAG,EAAI,KAAM,CAAE,CACnD"}
1
+ {"version":3,"file":"route.cjs","names":[],"sources":["../../../src/server/handlers/route.ts"],"sourcesContent":["import type { NextRequest } from 'next/server';\nimport type {\n\tAppRouterPageRoute,\n\tAppRouterPageRouteOpts,\n\tBaseServerSDK,\n\tPagesRouterRequest,\n\tWithAuthGuardAppRouter,\n\tWithAuthGuardAppRouterOptions,\n\tWithAuthGuardPageRouter,\n} from '../types';\nimport { isSessionExpired } from '@strivacity/sdk-core/utils';\n\n/**\n * Builds the Server SDK refresh route URL for an expired session. Guards cannot refresh in place: server components cannot set\n * cookies, so the rotated session would be lost. The refresh route writes the cookie and then redirects back to `returnTo`.\n *\n * @param {BaseServerSDK<NextRequest | Request | PagesRouterRequest | undefined>} sdk - The server SDK.\n * @param {string} returnTo - Where to return after the refresh.\n * @returns {string} The refresh route URL.\n */\nfunction refreshUrl(sdk: BaseServerSDK<NextRequest | Request | PagesRouterRequest | undefined>, returnTo: string): string {\n\treturn `${sdk.options.authUrlPrefix}/refresh?returnTo=${encodeURIComponent(returnTo)}`;\n}\n\nexport const appRouteHandlerFactory =\n\t(sdk: BaseServerSDK<NextRequest | Request | PagesRouterRequest | undefined>): WithAuthGuardAppRouter =>\n\t<P extends AppRouterPageRouteOpts = AppRouterPageRouteOpts>(handler: AppRouterPageRoute<P>, opts: WithAuthGuardAppRouterOptions<P> = {}) =>\n\tasync (params: P) => {\n\t\t// NOTE: Server Components cannot set cookies, so never refresh here: an expired session goes through the refresh route\n\t\tlet session = await sdk.getSession(undefined, { autoRefresh: false });\n\n\t\tif (session && isSessionExpired(session, sdk.options.refreshSkew)) {\n\t\t\tif (session.refresh_token && sdk.options.autoRefresh !== false) {\n\t\t\t\tconst returnTo = typeof opts.returnTo === 'function' ? await opts.returnTo(params) : opts.returnTo;\n\t\t\t\tconst { redirect } = await import('next/navigation');\n\n\t\t\t\tredirect(refreshUrl(sdk, returnTo || sdk.options.postLoginRedirectUri));\n\t\t\t}\n\n\t\t\tsession = null;\n\t\t}\n\n\t\tif (!session) {\n\t\t\tconst returnTo = typeof opts.returnTo === 'function' ? await opts.returnTo(params) : opts.returnTo;\n\t\t\tconst { redirect } = await import('next/navigation');\n\n\t\t\tredirect(`${sdk.options.loginUri}${returnTo ? `?returnTo=${encodeURIComponent(returnTo)}` : ''}`);\n\t\t}\n\n\t\treturn handler({ ...params, session });\n\t};\n\nexport const pageRouteHandlerFactory =\n\t(sdk: BaseServerSDK<NextRequest | Request | PagesRouterRequest | undefined>): WithAuthGuardPageRouter =>\n\t({ getServerSideProps, returnTo } = {}) =>\n\tasync (ctx) => {\n\t\t// NOTE: Server Components cannot set cookies, so never refresh here: an expired session goes through the refresh route\n\t\tconst session = await sdk.getSession(ctx.req, { autoRefresh: false });\n\n\t\tif (session && isSessionExpired(session, sdk.options.refreshSkew)) {\n\t\t\treturn {\n\t\t\t\tredirect: {\n\t\t\t\t\tdestination:\n\t\t\t\t\t\tsession.refresh_token && sdk.options.autoRefresh !== false\n\t\t\t\t\t\t\t? refreshUrl(sdk, returnTo || ctx.resolvedUrl)\n\t\t\t\t\t\t\t: `${sdk.options.loginUri}?returnTo=${encodeURIComponent(returnTo || ctx.resolvedUrl)}`,\n\t\t\t\t\tpermanent: false,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\tif (!session) {\n\t\t\treturn {\n\t\t\t\tredirect: {\n\t\t\t\t\tdestination: `${sdk.options.loginUri}?returnTo=${encodeURIComponent(returnTo || ctx.resolvedUrl)}`,\n\t\t\t\t\tpermanent: false,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\t\tlet ret: any = { props: {} };\n\n\t\tif (getServerSideProps) {\n\t\t\tret = await getServerSideProps(ctx);\n\t\t}\n\n\t\tif (ret.props instanceof Promise) {\n\t\t\tconst props = await ret.props;\n\n\t\t\treturn {\n\t\t\t\t...ret,\n\t\t\t\tprops: {\n\t\t\t\t\tsession,\n\t\t\t\t\t...props,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\treturn { ...ret, props: { session, ...ret.props } };\n\t};\n"],"mappings":"kYAoBA,SAAS,EAAW,EAA4E,EAA0B,CACzH,MAAO,GAAG,EAAI,QAAQ,cAAc,oBAAoB,mBAAmB,CAAQ,GACpF,CAEA,IAAa,EACX,IAC2D,EAAgC,EAAyC,CAAC,IACtI,KAAO,IAAc,CAEpB,IAAI,EAAU,MAAM,EAAI,WAAW,IAAA,GAAW,CAAE,YAAa,EAAM,CAAC,EAEpE,GAAI,IAAA,EAAW,EAAA,iBAAA,CAAiB,EAAS,EAAI,QAAQ,WAAW,EAAG,CAClE,GAAI,EAAQ,eAAiB,EAAI,QAAQ,cAAgB,GAAO,CAC/D,IAAM,EAAW,OAAO,EAAK,UAAa,WAAa,MAAM,EAAK,SAAS,CAAM,EAAI,EAAK,SACpF,CAAE,YAAA,MAAA,EAAA,SAAA,CAAF,GAAA,CAAE,YAAa,MAAM,OAAO,+CAElC,EAAS,EAAW,EAAK,GAAY,EAAI,QAAQ,oBAAoB,CAAC,CACvE,CAEA,EAAU,IACX,CAEA,GAAI,CAAC,EAAS,CACb,IAAM,EAAW,OAAO,EAAK,UAAa,WAAa,MAAM,EAAK,SAAS,CAAM,EAAI,EAAK,SACpF,CAAE,YAAA,MAAA,EAAA,SAAA,CAAF,GAAA,CAAE,YAAa,MAAM,OAAO,+CAElC,EAAS,GAAG,EAAI,QAAQ,WAAW,EAAW,aAAa,mBAAmB,CAAQ,IAAM,IAAI,CACjG,CAEA,OAAO,EAAQ,CAAE,GAAG,EAAQ,SAAQ,CAAC,CACtC,EAEY,EACX,IACA,CAAE,qBAAoB,YAAa,CAAC,IACrC,KAAO,IAAQ,CAEd,IAAM,EAAU,MAAM,EAAI,WAAW,EAAI,IAAK,CAAE,YAAa,EAAM,CAAC,EAEpE,GAAI,IAAA,EAAW,EAAA,iBAAA,CAAiB,EAAS,EAAI,QAAQ,WAAW,EAC/D,MAAO,CACN,SAAU,CACT,YACC,EAAQ,eAAiB,EAAI,QAAQ,cAAgB,GAClD,EAAW,EAAK,GAAY,EAAI,WAAW,EAC3C,GAAG,EAAI,QAAQ,SAAS,YAAY,mBAAmB,GAAY,EAAI,WAAW,IACtF,UAAW,EACZ,CACD,EAGD,GAAI,CAAC,EACJ,MAAO,CACN,SAAU,CACT,YAAa,GAAG,EAAI,QAAQ,SAAS,YAAY,mBAAmB,GAAY,EAAI,WAAW,IAC/F,UAAW,EACZ,CACD,EAID,IAAI,EAAW,CAAE,MAAO,CAAC,CAAE,EAM3B,GAJI,IACH,EAAM,MAAM,EAAmB,CAAG,GAG/B,EAAI,iBAAiB,QAAS,CACjC,IAAM,EAAQ,MAAM,EAAI,MAExB,MAAO,CACN,GAAG,EACH,MAAO,CACN,UACA,GAAG,CACJ,CACD,CACD,CAEA,MAAO,CAAE,GAAG,EAAK,MAAO,CAAE,UAAS,GAAG,EAAI,KAAM,CAAE,CACnD"}
@@ -1,2 +1,2 @@
1
- var e=function(e){return`/`+e},t={},n=function(n,r,i){let a=Promise.resolve();if(r&&r.length>0){let n=document.getElementsByTagName(`link`),o=document.querySelector(`meta[property=csp-nonce]`),s=o?.nonce||o?.getAttribute(`nonce`);function c(e){return Promise.all(e.map(e=>Promise.resolve(e).then(e=>({status:`fulfilled`,value:e}),e=>({status:`rejected`,reason:e}))))}function l(e){return import.meta.resolve?import.meta.resolve(e):new URL(e,import.meta.url).href}a=c(r.map(r=>{if(r=e(r,i),r=l(r),r in t)return;t[r]=!0;let a=r.endsWith(`.css`);for(let e=n.length-1;e>=0;e--){let t=n[e];if(t.href===r&&(!a||t.rel===`stylesheet`))return}let o=document.createElement(`link`);if(o.rel=a?`stylesheet`:`modulepreload`,a||(o.as=`script`),o.crossOrigin=``,o.href=r,s&&o.setAttribute(`nonce`,s),document.head.appendChild(o),a)return new Promise((e,t)=>{o.addEventListener(`load`,e),o.addEventListener(`error`,()=>t(Error(`Unable to preload CSS for ${r}`)))})}))}function o(e){let t=new Event(`vite:preloadError`,{cancelable:!0});if(t.payload=e,window.dispatchEvent(t),!t.defaultPrevented)throw e}return a.then(e=>{for(let t of e||[])t.status===`rejected`&&o(t.reason);return n().catch(o)})},r=e=>(t,r={})=>async i=>{let a=await e.getSession();if(!a){let t=typeof r.returnTo==`function`?await r.returnTo(i):r.returnTo,{redirect:a}=await n(async()=>{let{redirect:e}=await import(`next/navigation`);return{redirect:e}},[]);a(`${e.options.loginUri}${t?`?returnTo=${encodeURIComponent(t)}`:``}`)}return t({...i,session:a})},i=e=>({getServerSideProps:t,returnTo:n}={})=>async r=>{let i=await e.getSession();if(!i)return{redirect:{destination:`${e.options.loginUri}?returnTo=${encodeURIComponent(n||r.resolvedUrl)}`,permanent:!1}};let a={props:{}};if(t&&(a=await t(r)),a.props instanceof Promise){let e=await a.props;return{...a,props:{session:i,...e}}}return{...a,props:{session:i,...a.props}}};export{r as appRouteHandlerFactory,i as pageRouteHandlerFactory};
1
+ import{isSessionExpired as e}from"@strivacity/sdk-core/utils";var t=`modulepreload`,n=function(e){return`/`+e},r={},i=function(e,i,a){let o=Promise.resolve();if(i&&i.length>0){let e=document.getElementsByTagName(`link`),s=document.querySelector(`meta[property=csp-nonce]`),c=s?.nonce||s?.getAttribute(`nonce`);function l(e){return Promise.all(e.map(e=>Promise.resolve(e).then(e=>({status:`fulfilled`,value:e}),e=>({status:`rejected`,reason:e}))))}function u(e){return import.meta.resolve?import.meta.resolve(e):new URL(e,import.meta.url).href}o=l(i.map(i=>{if(i=n(i,a),i=u(i),i in r)return;r[i]=!0;let o=i.endsWith(`.css`);for(let t=e.length-1;t>=0;t--){let n=e[t];if(n.href===i&&(!o||n.rel===`stylesheet`))return}let s=document.createElement(`link`);if(s.rel=o?`stylesheet`:t,o||(s.as=`script`),s.crossOrigin=``,s.href=i,c&&s.setAttribute(`nonce`,c),document.head.appendChild(s),o)return new Promise((e,t)=>{s.addEventListener(`load`,e),s.addEventListener(`error`,()=>t(Error(`Unable to preload CSS for ${i}`)))})}))}function s(e){let t=new Event(`vite:preloadError`,{cancelable:!0});if(t.payload=e,window.dispatchEvent(t),!t.defaultPrevented)throw e}return o.then(t=>{for(let e of t||[])e.status===`rejected`&&s(e.reason);return e().catch(s)})};function a(e,t){return`${e.options.authUrlPrefix}/refresh?returnTo=${encodeURIComponent(t)}`}var o=t=>(n,r={})=>async o=>{let s=await t.getSession(void 0,{autoRefresh:!1});if(s&&e(s,t.options.refreshSkew)){if(s.refresh_token&&t.options.autoRefresh!==!1){let e=typeof r.returnTo==`function`?await r.returnTo(o):r.returnTo,{redirect:n}=await i(async()=>{let{redirect:e}=await import(`next/navigation`);return{redirect:e}},[]);n(a(t,e||t.options.postLoginRedirectUri))}s=null}if(!s){let e=typeof r.returnTo==`function`?await r.returnTo(o):r.returnTo,{redirect:n}=await i(async()=>{let{redirect:e}=await import(`next/navigation`);return{redirect:e}},[]);n(`${t.options.loginUri}${e?`?returnTo=${encodeURIComponent(e)}`:``}`)}return n({...o,session:s})},s=t=>({getServerSideProps:n,returnTo:r}={})=>async i=>{let o=await t.getSession(i.req,{autoRefresh:!1});if(o&&e(o,t.options.refreshSkew))return{redirect:{destination:o.refresh_token&&t.options.autoRefresh!==!1?a(t,r||i.resolvedUrl):`${t.options.loginUri}?returnTo=${encodeURIComponent(r||i.resolvedUrl)}`,permanent:!1}};if(!o)return{redirect:{destination:`${t.options.loginUri}?returnTo=${encodeURIComponent(r||i.resolvedUrl)}`,permanent:!1}};let s={props:{}};if(n&&(s=await n(i)),s.props instanceof Promise){let e=await s.props;return{...s,props:{session:o,...e}}}return{...s,props:{session:o,...s.props}}};export{o as appRouteHandlerFactory,s as pageRouteHandlerFactory};
2
2
  //# sourceMappingURL=route.mjs.map
@@ -1 +1 @@
1
- {"version":3,"mappings":"6pCAWa,EACX,IAC2D,EAAgC,EAAyC,CAAC,IACtI,KAAO,IAAc,CACpB,IAAM,EAAU,MAAM,EAAI,WAAW,EAErC,GAAI,CAAC,EAAS,CACb,IAAM,EAAW,OAAO,EAAK,UAAa,WAAa,MAAM,EAAK,SAAS,CAAM,EAAI,EAAK,SACpF,CAAE,8BAAF,IAAE,YAAa,MAAM,OAAO,2CAElC,EAAS,GAAG,EAAI,QAAQ,WAAW,EAAW,aAAa,mBAAmB,CAAQ,IAAM,IAAI,CACjG,CAEA,OAAO,EAAQ,CAAE,GAAG,EAAQ,SAAQ,CAAC,CACtC,EAEY,EACX,IACA,CAAE,qBAAoB,YAAa,CAAC,IACrC,KAAO,IAAQ,CACd,IAAM,EAAU,MAAM,EAAI,WAAW,EAErC,GAAI,CAAC,EACJ,MAAO,CACN,SAAU,CACT,YAAa,GAAG,EAAI,QAAQ,SAAS,YAAY,mBAAmB,GAAY,EAAI,WAAW,IAC/F,UAAW,EACZ,CACD,EAID,IAAI,EAAW,CAAE,MAAO,CAAC,CAAE,EAM3B,GAJI,IACH,EAAM,MAAM,EAAmB,CAAG,GAG/B,EAAI,iBAAiB,QAAS,CACjC,IAAM,EAAQ,MAAM,EAAI,MAExB,MAAO,CACN,GAAG,EACH,MAAO,CACN,UACA,GAAG,CACJ,CACD,CACD,CAEA,MAAO,CAAE,GAAG,EAAK,MAAO,CAAE,UAAS,GAAG,EAAI,KAAM,CAAE,CACnD","names":[],"ignoreList":[],"sources":["../../../src/server/handlers/route.ts"],"sourcesContent":["import type { NextRequest } from 'next/server';\nimport type {\n\tAppRouterPageRoute,\n\tAppRouterPageRouteOpts,\n\tBaseServerSDK,\n\tPagesRouterRequest,\n\tWithAuthGuardAppRouter,\n\tWithAuthGuardAppRouterOptions,\n\tWithAuthGuardPageRouter,\n} from '../types';\n\nexport const appRouteHandlerFactory =\n\t(sdk: BaseServerSDK<NextRequest | Request | PagesRouterRequest | undefined>): WithAuthGuardAppRouter =>\n\t<P extends AppRouterPageRouteOpts = AppRouterPageRouteOpts>(handler: AppRouterPageRoute<P>, opts: WithAuthGuardAppRouterOptions<P> = {}) =>\n\tasync (params: P) => {\n\t\tconst session = await sdk.getSession();\n\n\t\tif (!session) {\n\t\t\tconst returnTo = typeof opts.returnTo === 'function' ? await opts.returnTo(params) : opts.returnTo;\n\t\t\tconst { redirect } = await import('next/navigation');\n\n\t\t\tredirect(`${sdk.options.loginUri}${returnTo ? `?returnTo=${encodeURIComponent(returnTo)}` : ''}`);\n\t\t}\n\n\t\treturn handler({ ...params, session });\n\t};\n\nexport const pageRouteHandlerFactory =\n\t(sdk: BaseServerSDK<NextRequest | Request | PagesRouterRequest | undefined>): WithAuthGuardPageRouter =>\n\t({ getServerSideProps, returnTo } = {}) =>\n\tasync (ctx) => {\n\t\tconst session = await sdk.getSession();\n\n\t\tif (!session) {\n\t\t\treturn {\n\t\t\t\tredirect: {\n\t\t\t\t\tdestination: `${sdk.options.loginUri}?returnTo=${encodeURIComponent(returnTo || ctx.resolvedUrl)}`,\n\t\t\t\t\tpermanent: false,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\t\tlet ret: any = { props: {} };\n\n\t\tif (getServerSideProps) {\n\t\t\tret = await getServerSideProps(ctx);\n\t\t}\n\n\t\tif (ret.props instanceof Promise) {\n\t\t\tconst props = await ret.props;\n\n\t\t\treturn {\n\t\t\t\t...ret,\n\t\t\t\tprops: {\n\t\t\t\t\tsession,\n\t\t\t\t\t...props,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\treturn { ...ret, props: { session, ...ret.props } };\n\t};\n"],"file":"route.mjs"}
1
+ {"version":3,"mappings":"+tCAoBA,SAAS,EAAW,EAA4E,EAA0B,CACzH,MAAO,GAAG,EAAI,QAAQ,cAAc,oBAAoB,mBAAmB,CAAQ,GACpF,CAEA,IAAa,EACX,IAC2D,EAAgC,EAAyC,CAAC,IACtI,KAAO,IAAc,CAEpB,IAAI,EAAU,MAAM,EAAI,WAAW,OAAW,CAAE,YAAa,EAAM,CAAC,EAEpE,GAAI,GAAW,EAAiB,EAAS,EAAI,QAAQ,WAAW,EAAG,CAClE,GAAI,EAAQ,eAAiB,EAAI,QAAQ,cAAgB,GAAO,CAC/D,IAAM,EAAW,OAAO,EAAK,UAAa,WAAa,MAAM,EAAK,SAAS,CAAM,EAAI,EAAK,SACpF,CAAE,8BAAF,IAAE,YAAa,MAAM,OAAO,2CAElC,EAAS,EAAW,EAAK,GAAY,EAAI,QAAQ,oBAAoB,CAAC,CACvE,CAEA,EAAU,IACX,CAEA,GAAI,CAAC,EAAS,CACb,IAAM,EAAW,OAAO,EAAK,UAAa,WAAa,MAAM,EAAK,SAAS,CAAM,EAAI,EAAK,SACpF,CAAE,8BAAF,IAAE,YAAa,MAAM,OAAO,2CAElC,EAAS,GAAG,EAAI,QAAQ,WAAW,EAAW,aAAa,mBAAmB,CAAQ,IAAM,IAAI,CACjG,CAEA,OAAO,EAAQ,CAAE,GAAG,EAAQ,SAAQ,CAAC,CACtC,EAEY,EACX,IACA,CAAE,qBAAoB,YAAa,CAAC,IACrC,KAAO,IAAQ,CAEd,IAAM,EAAU,MAAM,EAAI,WAAW,EAAI,IAAK,CAAE,YAAa,EAAM,CAAC,EAEpE,GAAI,GAAW,EAAiB,EAAS,EAAI,QAAQ,WAAW,EAC/D,MAAO,CACN,SAAU,CACT,YACC,EAAQ,eAAiB,EAAI,QAAQ,cAAgB,GAClD,EAAW,EAAK,GAAY,EAAI,WAAW,EAC3C,GAAG,EAAI,QAAQ,SAAS,YAAY,mBAAmB,GAAY,EAAI,WAAW,IACtF,UAAW,EACZ,CACD,EAGD,GAAI,CAAC,EACJ,MAAO,CACN,SAAU,CACT,YAAa,GAAG,EAAI,QAAQ,SAAS,YAAY,mBAAmB,GAAY,EAAI,WAAW,IAC/F,UAAW,EACZ,CACD,EAID,IAAI,EAAW,CAAE,MAAO,CAAC,CAAE,EAM3B,GAJI,IACH,EAAM,MAAM,EAAmB,CAAG,GAG/B,EAAI,iBAAiB,QAAS,CACjC,IAAM,EAAQ,MAAM,EAAI,MAExB,MAAO,CACN,GAAG,EACH,MAAO,CACN,UACA,GAAG,CACJ,CACD,CACD,CAEA,MAAO,CAAE,GAAG,EAAK,MAAO,CAAE,UAAS,GAAG,EAAI,KAAM,CAAE,CACnD","names":[],"ignoreList":[],"sources":["../../../src/server/handlers/route.ts"],"sourcesContent":["import type { NextRequest } from 'next/server';\nimport type {\n\tAppRouterPageRoute,\n\tAppRouterPageRouteOpts,\n\tBaseServerSDK,\n\tPagesRouterRequest,\n\tWithAuthGuardAppRouter,\n\tWithAuthGuardAppRouterOptions,\n\tWithAuthGuardPageRouter,\n} from '../types';\nimport { isSessionExpired } from '@strivacity/sdk-core/utils';\n\n/**\n * Builds the Server SDK refresh route URL for an expired session. Guards cannot refresh in place: server components cannot set\n * cookies, so the rotated session would be lost. The refresh route writes the cookie and then redirects back to `returnTo`.\n *\n * @param {BaseServerSDK<NextRequest | Request | PagesRouterRequest | undefined>} sdk - The server SDK.\n * @param {string} returnTo - Where to return after the refresh.\n * @returns {string} The refresh route URL.\n */\nfunction refreshUrl(sdk: BaseServerSDK<NextRequest | Request | PagesRouterRequest | undefined>, returnTo: string): string {\n\treturn `${sdk.options.authUrlPrefix}/refresh?returnTo=${encodeURIComponent(returnTo)}`;\n}\n\nexport const appRouteHandlerFactory =\n\t(sdk: BaseServerSDK<NextRequest | Request | PagesRouterRequest | undefined>): WithAuthGuardAppRouter =>\n\t<P extends AppRouterPageRouteOpts = AppRouterPageRouteOpts>(handler: AppRouterPageRoute<P>, opts: WithAuthGuardAppRouterOptions<P> = {}) =>\n\tasync (params: P) => {\n\t\t// NOTE: Server Components cannot set cookies, so never refresh here: an expired session goes through the refresh route\n\t\tlet session = await sdk.getSession(undefined, { autoRefresh: false });\n\n\t\tif (session && isSessionExpired(session, sdk.options.refreshSkew)) {\n\t\t\tif (session.refresh_token && sdk.options.autoRefresh !== false) {\n\t\t\t\tconst returnTo = typeof opts.returnTo === 'function' ? await opts.returnTo(params) : opts.returnTo;\n\t\t\t\tconst { redirect } = await import('next/navigation');\n\n\t\t\t\tredirect(refreshUrl(sdk, returnTo || sdk.options.postLoginRedirectUri));\n\t\t\t}\n\n\t\t\tsession = null;\n\t\t}\n\n\t\tif (!session) {\n\t\t\tconst returnTo = typeof opts.returnTo === 'function' ? await opts.returnTo(params) : opts.returnTo;\n\t\t\tconst { redirect } = await import('next/navigation');\n\n\t\t\tredirect(`${sdk.options.loginUri}${returnTo ? `?returnTo=${encodeURIComponent(returnTo)}` : ''}`);\n\t\t}\n\n\t\treturn handler({ ...params, session });\n\t};\n\nexport const pageRouteHandlerFactory =\n\t(sdk: BaseServerSDK<NextRequest | Request | PagesRouterRequest | undefined>): WithAuthGuardPageRouter =>\n\t({ getServerSideProps, returnTo } = {}) =>\n\tasync (ctx) => {\n\t\t// NOTE: Server Components cannot set cookies, so never refresh here: an expired session goes through the refresh route\n\t\tconst session = await sdk.getSession(ctx.req, { autoRefresh: false });\n\n\t\tif (session && isSessionExpired(session, sdk.options.refreshSkew)) {\n\t\t\treturn {\n\t\t\t\tredirect: {\n\t\t\t\t\tdestination:\n\t\t\t\t\t\tsession.refresh_token && sdk.options.autoRefresh !== false\n\t\t\t\t\t\t\t? refreshUrl(sdk, returnTo || ctx.resolvedUrl)\n\t\t\t\t\t\t\t: `${sdk.options.loginUri}?returnTo=${encodeURIComponent(returnTo || ctx.resolvedUrl)}`,\n\t\t\t\t\tpermanent: false,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\tif (!session) {\n\t\t\treturn {\n\t\t\t\tredirect: {\n\t\t\t\t\tdestination: `${sdk.options.loginUri}?returnTo=${encodeURIComponent(returnTo || ctx.resolvedUrl)}`,\n\t\t\t\t\tpermanent: false,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\t\tlet ret: any = { props: {} };\n\n\t\tif (getServerSideProps) {\n\t\t\tret = await getServerSideProps(ctx);\n\t\t}\n\n\t\tif (ret.props instanceof Promise) {\n\t\t\tconst props = await ret.props;\n\n\t\t\treturn {\n\t\t\t\t...ret,\n\t\t\t\tprops: {\n\t\t\t\t\tsession,\n\t\t\t\t\t...props,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\treturn { ...ret, props: { session, ...ret.props } };\n\t};\n"],"file":"route.mjs"}
@@ -1,2 +1,2 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./storages.cjs"),t=require("./handlers/api.cjs"),n=require("./handlers/route.cjs");let r=require("@strivacity/sdk-core/utils/errors"),i=require("next/server"),a=require("@strivacity/sdk-core/server");function o(o){if(!o.storage){if(!o.secret)throw new r.ConfigurationError(`Secret is required for encrypted cookie storage`);o.cookieMaxAge??=2592e3,o.storage=e.createEncryptedCookieStorage(o.secret,{defaultCookieOptions:{maxAge:o.cookieMaxAge}})}let s=(0,a.createBaseServerSDK)({toRequest:e=>e,redirect:(e,t)=>i.NextResponse.redirect(e,t)},o);function c(e){return(n,r)=>n instanceof Request?t.apiAppRouteHandlerFactory(s)(e)(n,r??{}):t.apiPageRouteHandlerFactory(s)(e)(n,r)}function l(e,t){return typeof e==`function`?n.appRouteHandlerFactory(s)(e,t):n.pageRouteHandlerFactory(s)(e)}return{get options(){return s.options},withAuthGuard:l,withApiAuthRequired:c,getSession:e=>s.getSession(e),updateSession:(e,t)=>s.updateSession(e,t),refreshSession:e=>s.refreshSession(e),revokeSession:e=>s.revokeSession(e),getEntrySession:e=>s.getEntrySession(e),completeLogin:(e,t)=>s.completeLogin(e,t),logout:(e,t)=>s.logout(e,t),handleLogin:e=>s.handleLogin(e),handleRegister:e=>s.handleRegister(e),handleCallback:e=>s.handleCallback(e),handleRefresh:e=>s.handleRefresh(e),handleRevoke:e=>s.handleRevoke(e),handleEntry:e=>s.handleEntry(e),handleLogout:e=>s.handleLogout(e),handleBackChannelLogout:e=>s.handleBackChannelLogout(e),handler:async e=>await s.handler(e)??new i.NextResponse(`Not Found`,{status:404})}}exports.createServerSDK=o;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./storages.cjs"),t=require("./handlers/api.cjs"),n=require("./handlers/route.cjs");let r=require("@strivacity/sdk-core/utils/errors"),i=require("next/server"),a=require("@strivacity/sdk-core/server");function o(o){if(!o.storage){if(!o.secret)throw new r.ConfigurationError(`Secret is required for encrypted cookie storage`);o.cookieMaxAge??=2592e3,o.storage=e.createEncryptedCookieStorage(o.secret,{defaultCookieOptions:{maxAge:o.cookieMaxAge}})}let s=(0,a.createBaseServerSDK)({toRequest:e=>e,redirect:(e,t)=>i.NextResponse.redirect(e,t)},o);function c(e){return(n,r)=>n instanceof Request?t.apiAppRouteHandlerFactory(s)(e)(n,r??{}):t.apiPageRouteHandlerFactory(s)(e)(n,r)}function l(e,t){return typeof e==`function`?n.appRouteHandlerFactory(s)(e,t):n.pageRouteHandlerFactory(s)(e)}return{get options(){return s.options},withAuthGuard:l,withApiAuthRequired:c,getSession:(e,t)=>s.getSession(e,e instanceof Request?t:{autoRefresh:!1}),updateSession:(e,t)=>s.updateSession(e,t),refreshSession:e=>s.refreshSession(e),revokeSession:e=>s.revokeSession(e),getEntrySession:e=>s.getEntrySession(e),completeLogin:(e,t)=>s.completeLogin(e,t),logout:(e,t)=>s.logout(e,t),handleLogin:e=>s.handleLogin(e),handleRegister:e=>s.handleRegister(e),handleCallback:e=>s.handleCallback(e),handleRefresh:e=>s.handleRefresh(e),handleRevoke:e=>s.handleRevoke(e),handleEntry:e=>s.handleEntry(e),handleLogout:e=>s.handleLogout(e),handleBackChannelLogout:e=>s.handleBackChannelLogout(e),handler:async e=>await s.handler(e)??new i.NextResponse(`Not Found`,{status:404})}}exports.createServerSDK=o;
2
2
  //# sourceMappingURL=sdk.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"sdk.cjs","names":[],"sources":["../../src/server/sdk.ts"],"sourcesContent":["import type { NextApiHandler, NextApiRequest, NextApiResponse } from 'next';\nimport type { ParsedUrlQuery } from 'node:querystring';\nimport type {\n\tNextServerSDK,\n\tNextServerSDKInitConfig,\n\tWithAuthGuardAppRouterOptions,\n\tWithAuthGuardPageRouterOptions,\n\tAppRouterPageRoute,\n\tAppRouterPageRouteOpts,\n\tPageRoute,\n\tAppRouteHandlerFn,\n\tAppRouteHandlerFnContext,\n\tPagesRouterRequest,\n} from './types';\nimport { NextResponse, type NextRequest } from 'next/server';\nimport { createBaseServerSDK } from '@strivacity/sdk-core/server';\nimport { ConfigurationError } from '@strivacity/sdk-core/utils/errors';\nimport { createEncryptedCookieStorage } from './storages';\nimport { apiAppRouteHandlerFactory, apiPageRouteHandlerFactory } from './handlers/api';\nimport { appRouteHandlerFactory, pageRouteHandlerFactory } from './handlers/route';\n\n/**\n * Creates a Next.js server SDK instance with the provided configuration.\n *\n * @param {NextServerSDKInitConfig} initConfig - The initialization configuration for the SDK.\n * @returns {NextServerSDK} The initialized Next.js server SDK instance.\n */\nexport function createServerSDK(initConfig: NextServerSDKInitConfig): NextServerSDK {\n\tif (!initConfig.storage) {\n\t\tif (!initConfig.secret) {\n\t\t\tthrow new ConfigurationError('Secret is required for encrypted cookie storage');\n\t\t}\n\n\t\tinitConfig.cookieMaxAge ??= 30 * 24 * 60 * 60;\n\t\tinitConfig.storage = createEncryptedCookieStorage(initConfig.secret, { defaultCookieOptions: { maxAge: initConfig.cookieMaxAge } });\n\t}\n\n\tconst base = createBaseServerSDK<NextRequest | Request | PagesRouterRequest | undefined>(\n\t\t{\n\t\t\ttoRequest: (req) => req as Request,\n\t\t\tredirect: (url, status) => NextResponse.redirect(url, status),\n\t\t},\n\t\tinitConfig,\n\t);\n\n\tfunction withApiAuthRequired(apiRoute: AppRouteHandlerFn): AppRouteHandlerFn;\n\tfunction withApiAuthRequired(apiRoute: NextApiHandler): NextApiHandler;\n\tfunction withApiAuthRequired(apiRoute: AppRouteHandlerFn | NextApiHandler): AppRouteHandlerFn | NextApiHandler {\n\t\treturn (req: NextRequest | Request | NextApiRequest, resOrCtx?: AppRouteHandlerFnContext | NextApiResponse) => {\n\t\t\tif (req instanceof Request) {\n\t\t\t\tconst appRouteHandler = apiAppRouteHandlerFactory(base);\n\t\t\t\tconst wrappedAppRoute = appRouteHandler(apiRoute as AppRouteHandlerFn);\n\t\t\t\treturn wrappedAppRoute(req, (resOrCtx ?? {}) as AppRouteHandlerFnContext);\n\t\t\t}\n\n\t\t\tconst pageRouteHandler = apiPageRouteHandlerFactory(base);\n\t\t\tconst wrappedPageRoute = pageRouteHandler(apiRoute as NextApiHandler);\n\t\t\treturn wrappedPageRoute(req, resOrCtx as NextApiResponse);\n\t\t};\n\t}\n\n\tfunction withAuthGuard(): PageRoute<Record<string, unknown>, ParsedUrlQuery>;\n\tfunction withAuthGuard<P extends Record<string, unknown> = Record<string, unknown>, Q extends ParsedUrlQuery = ParsedUrlQuery>(\n\t\topts: WithAuthGuardPageRouterOptions<P, Q>,\n\t): PageRoute<P, Q>;\n\tfunction withAuthGuard<P extends AppRouterPageRouteOpts = AppRouterPageRouteOpts>(\n\t\tfn: AppRouterPageRoute<P>,\n\t\topts?: WithAuthGuardAppRouterOptions<P>,\n\t): AppRouterPageRoute<P>;\n\tfunction withAuthGuard(\n\t\tfnOrOpts?: WithAuthGuardPageRouterOptions | AppRouterPageRoute,\n\t\topts?: WithAuthGuardAppRouterOptions,\n\t): PageRoute<Record<string, unknown>> | AppRouterPageRoute {\n\t\tif (typeof fnOrOpts === 'function') {\n\t\t\tconst appRouteHandler = appRouteHandlerFactory(base);\n\t\t\treturn appRouteHandler(fnOrOpts, opts);\n\t\t}\n\n\t\tconst pageRouteHandler = pageRouteHandlerFactory(base);\n\t\treturn pageRouteHandler(fnOrOpts);\n\t}\n\n\treturn {\n\t\tget options() {\n\t\t\treturn base.options;\n\t\t},\n\t\twithAuthGuard,\n\t\twithApiAuthRequired,\n\t\tgetSession: (req) => base.getSession(req),\n\t\tupdateSession: (event, session) => base.updateSession(event, session),\n\t\trefreshSession: (req) => base.refreshSession(req),\n\t\trevokeSession: (req) => base.revokeSession(req),\n\t\tgetEntrySession: (entryUrl) => base.getEntrySession(entryUrl),\n\t\tcompleteLogin: (params, req) => base.completeLogin(params, req),\n\t\tlogout: (postLogoutRedirectUri, req) => base.logout(postLogoutRedirectUri, req),\n\t\thandleLogin: (req) => base.handleLogin(req),\n\t\thandleRegister: (req) => base.handleRegister(req),\n\t\thandleCallback: (req) => base.handleCallback(req),\n\t\thandleRefresh: (req) => base.handleRefresh(req),\n\t\thandleRevoke: (req) => base.handleRevoke(req),\n\t\thandleEntry: (req) => base.handleEntry(req),\n\t\thandleLogout: (req) => base.handleLogout(req),\n\t\thandleBackChannelLogout: (req) => base.handleBackChannelLogout(req),\n\t\thandler: async (req) => (await base.handler(req)) ?? new NextResponse('Not Found', { status: 404 }),\n\t};\n}\n"],"mappings":"4RA2BA,SAAgB,EAAgB,EAAoD,CACnF,GAAI,CAAC,EAAW,QAAS,CACxB,GAAI,CAAC,EAAW,OACf,MAAM,IAAI,EAAA,mBAAmB,iDAAiD,EAG/E,EAAW,eAAiB,OAC5B,EAAW,QAAU,EAAA,6BAA6B,EAAW,OAAQ,CAAE,qBAAsB,CAAE,OAAQ,EAAW,YAAa,CAAE,CAAC,CACnI,CAEA,IAAM,GAAA,EAAO,EAAA,oBAAA,CACZ,CACC,UAAY,GAAQ,EACpB,UAAW,EAAK,IAAW,EAAA,aAAa,SAAS,EAAK,CAAM,CAC7D,EACA,CACD,EAIA,SAAS,EAAoB,EAAkF,CAC9G,OAAQ,EAA6C,IAChD,aAAe,QACM,EAAA,0BAA0B,CAC1B,CAAA,CAAgB,CACjC,CAAA,CAAgB,EAAM,GAAY,CAAC,CAA8B,EAGhD,EAAA,2BAA2B,CAC3B,CAAA,CAAiB,CACnC,CAAA,CAAiB,EAAK,CAA2B,CAE1D,CAUA,SAAS,EACR,EACA,EAC0D,CAO1D,OANI,OAAO,GAAa,WACC,EAAA,uBAAuB,CACxC,CAAA,CAAgB,EAAU,CAAI,EAGb,EAAA,wBAAwB,CAC1C,CAAA,CAAiB,CAAQ,CACjC,CAEA,MAAO,CACN,IAAI,SAAU,CACb,OAAO,EAAK,OACb,EACA,gBACA,sBACA,WAAa,GAAQ,EAAK,WAAW,CAAG,EACxC,eAAgB,EAAO,IAAY,EAAK,cAAc,EAAO,CAAO,EACpE,eAAiB,GAAQ,EAAK,eAAe,CAAG,EAChD,cAAgB,GAAQ,EAAK,cAAc,CAAG,EAC9C,gBAAkB,GAAa,EAAK,gBAAgB,CAAQ,EAC5D,eAAgB,EAAQ,IAAQ,EAAK,cAAc,EAAQ,CAAG,EAC9D,QAAS,EAAuB,IAAQ,EAAK,OAAO,EAAuB,CAAG,EAC9E,YAAc,GAAQ,EAAK,YAAY,CAAG,EAC1C,eAAiB,GAAQ,EAAK,eAAe,CAAG,EAChD,eAAiB,GAAQ,EAAK,eAAe,CAAG,EAChD,cAAgB,GAAQ,EAAK,cAAc,CAAG,EAC9C,aAAe,GAAQ,EAAK,aAAa,CAAG,EAC5C,YAAc,GAAQ,EAAK,YAAY,CAAG,EAC1C,aAAe,GAAQ,EAAK,aAAa,CAAG,EAC5C,wBAA0B,GAAQ,EAAK,wBAAwB,CAAG,EAClE,QAAS,KAAO,IAAS,MAAM,EAAK,QAAQ,CAAG,GAAM,IAAI,EAAA,aAAa,YAAa,CAAE,OAAQ,GAAI,CAAC,CACnG,CACD"}
1
+ {"version":3,"file":"sdk.cjs","names":[],"sources":["../../src/server/sdk.ts"],"sourcesContent":["import type { NextApiHandler, NextApiRequest, NextApiResponse } from 'next';\nimport type { ParsedUrlQuery } from 'node:querystring';\nimport type {\n\tNextServerSDK,\n\tNextServerSDKInitConfig,\n\tWithAuthGuardAppRouterOptions,\n\tWithAuthGuardPageRouterOptions,\n\tAppRouterPageRoute,\n\tAppRouterPageRouteOpts,\n\tPageRoute,\n\tAppRouteHandlerFn,\n\tAppRouteHandlerFnContext,\n\tPagesRouterRequest,\n} from './types';\nimport { NextResponse, type NextRequest } from 'next/server';\nimport { createBaseServerSDK } from '@strivacity/sdk-core/server';\nimport { ConfigurationError } from '@strivacity/sdk-core/utils/errors';\nimport { createEncryptedCookieStorage } from './storages';\nimport { apiAppRouteHandlerFactory, apiPageRouteHandlerFactory } from './handlers/api';\nimport { appRouteHandlerFactory, pageRouteHandlerFactory } from './handlers/route';\n\n/**\n * Creates a Next.js server SDK instance with the provided configuration.\n *\n * @param {NextServerSDKInitConfig} initConfig - The initialization configuration for the SDK.\n * @returns {NextServerSDK} The initialized Next.js server SDK instance.\n */\nexport function createServerSDK(initConfig: NextServerSDKInitConfig): NextServerSDK {\n\tif (!initConfig.storage) {\n\t\tif (!initConfig.secret) {\n\t\t\tthrow new ConfigurationError('Secret is required for encrypted cookie storage');\n\t\t}\n\n\t\tinitConfig.cookieMaxAge ??= 30 * 24 * 60 * 60;\n\t\tinitConfig.storage = createEncryptedCookieStorage(initConfig.secret, { defaultCookieOptions: { maxAge: initConfig.cookieMaxAge } });\n\t}\n\n\tconst base = createBaseServerSDK<NextRequest | Request | PagesRouterRequest | undefined>(\n\t\t{\n\t\t\ttoRequest: (req) => req as Request,\n\t\t\tredirect: (url, status) => NextResponse.redirect(url, status),\n\t\t},\n\t\tinitConfig,\n\t);\n\n\tfunction withApiAuthRequired(apiRoute: AppRouteHandlerFn): AppRouteHandlerFn;\n\tfunction withApiAuthRequired(apiRoute: NextApiHandler): NextApiHandler;\n\tfunction withApiAuthRequired(apiRoute: AppRouteHandlerFn | NextApiHandler): AppRouteHandlerFn | NextApiHandler {\n\t\treturn (req: NextRequest | Request | NextApiRequest, resOrCtx?: AppRouteHandlerFnContext | NextApiResponse) => {\n\t\t\tif (req instanceof Request) {\n\t\t\t\tconst appRouteHandler = apiAppRouteHandlerFactory(base);\n\t\t\t\tconst wrappedAppRoute = appRouteHandler(apiRoute as AppRouteHandlerFn);\n\t\t\t\treturn wrappedAppRoute(req, (resOrCtx ?? {}) as AppRouteHandlerFnContext);\n\t\t\t}\n\n\t\t\tconst pageRouteHandler = apiPageRouteHandlerFactory(base);\n\t\t\tconst wrappedPageRoute = pageRouteHandler(apiRoute as NextApiHandler);\n\t\t\treturn wrappedPageRoute(req, resOrCtx as NextApiResponse);\n\t\t};\n\t}\n\n\tfunction withAuthGuard(): PageRoute<Record<string, unknown>, ParsedUrlQuery>;\n\tfunction withAuthGuard<P extends Record<string, unknown> = Record<string, unknown>, Q extends ParsedUrlQuery = ParsedUrlQuery>(\n\t\topts: WithAuthGuardPageRouterOptions<P, Q>,\n\t): PageRoute<P, Q>;\n\tfunction withAuthGuard<P extends AppRouterPageRouteOpts = AppRouterPageRouteOpts>(\n\t\tfn: AppRouterPageRoute<P>,\n\t\topts?: WithAuthGuardAppRouterOptions<P>,\n\t): AppRouterPageRoute<P>;\n\tfunction withAuthGuard(\n\t\tfnOrOpts?: WithAuthGuardPageRouterOptions | AppRouterPageRoute,\n\t\topts?: WithAuthGuardAppRouterOptions,\n\t): PageRoute<Record<string, unknown>> | AppRouterPageRoute {\n\t\tif (typeof fnOrOpts === 'function') {\n\t\t\tconst appRouteHandler = appRouteHandlerFactory(base);\n\t\t\treturn appRouteHandler(fnOrOpts, opts);\n\t\t}\n\n\t\tconst pageRouteHandler = pageRouteHandlerFactory(base);\n\t\treturn pageRouteHandler(fnOrOpts);\n\t}\n\n\treturn {\n\t\tget options() {\n\t\t\treturn base.options;\n\t\t},\n\t\twithAuthGuard,\n\t\twithApiAuthRequired,\n\t\t// NOTE: refreshes (with autoRefresh) only for App Router requests, whose route handlers can write the rotated cookie.\n\t\t// Server Components (no request) and Pages Router requests read the stored session: a refresh there could not be saved.\n\t\tgetSession: (req, params) => base.getSession(req, req instanceof Request ? params : { autoRefresh: false }),\n\t\tupdateSession: (session, req) => base.updateSession(session, req),\n\t\trefreshSession: (req) => base.refreshSession(req),\n\t\trevokeSession: (req) => base.revokeSession(req),\n\t\tgetEntrySession: (entryUrl) => base.getEntrySession(entryUrl),\n\t\tcompleteLogin: (params, req) => base.completeLogin(params, req),\n\t\tlogout: (postLogoutRedirectUri, req) => base.logout(postLogoutRedirectUri, req),\n\t\thandleLogin: (req) => base.handleLogin(req),\n\t\thandleRegister: (req) => base.handleRegister(req),\n\t\thandleCallback: (req) => base.handleCallback(req),\n\t\thandleRefresh: (req) => base.handleRefresh(req),\n\t\thandleRevoke: (req) => base.handleRevoke(req),\n\t\thandleEntry: (req) => base.handleEntry(req),\n\t\thandleLogout: (req) => base.handleLogout(req),\n\t\thandleBackChannelLogout: (req) => base.handleBackChannelLogout(req),\n\t\thandler: async (req) => (await base.handler(req)) ?? new NextResponse('Not Found', { status: 404 }),\n\t};\n}\n"],"mappings":"4RA2BA,SAAgB,EAAgB,EAAoD,CACnF,GAAI,CAAC,EAAW,QAAS,CACxB,GAAI,CAAC,EAAW,OACf,MAAM,IAAI,EAAA,mBAAmB,iDAAiD,EAG/E,EAAW,eAAiB,OAC5B,EAAW,QAAU,EAAA,6BAA6B,EAAW,OAAQ,CAAE,qBAAsB,CAAE,OAAQ,EAAW,YAAa,CAAE,CAAC,CACnI,CAEA,IAAM,GAAA,EAAO,EAAA,oBAAA,CACZ,CACC,UAAY,GAAQ,EACpB,UAAW,EAAK,IAAW,EAAA,aAAa,SAAS,EAAK,CAAM,CAC7D,EACA,CACD,EAIA,SAAS,EAAoB,EAAkF,CAC9G,OAAQ,EAA6C,IAChD,aAAe,QACM,EAAA,0BAA0B,CAC1B,CAAA,CAAgB,CACjC,CAAA,CAAgB,EAAM,GAAY,CAAC,CAA8B,EAGhD,EAAA,2BAA2B,CAC3B,CAAA,CAAiB,CACnC,CAAA,CAAiB,EAAK,CAA2B,CAE1D,CAUA,SAAS,EACR,EACA,EAC0D,CAO1D,OANI,OAAO,GAAa,WACC,EAAA,uBAAuB,CACxC,CAAA,CAAgB,EAAU,CAAI,EAGb,EAAA,wBAAwB,CAC1C,CAAA,CAAiB,CAAQ,CACjC,CAEA,MAAO,CACN,IAAI,SAAU,CACb,OAAO,EAAK,OACb,EACA,gBACA,sBAGA,YAAa,EAAK,IAAW,EAAK,WAAW,EAAK,aAAe,QAAU,EAAS,CAAE,YAAa,EAAM,CAAC,EAC1G,eAAgB,EAAS,IAAQ,EAAK,cAAc,EAAS,CAAG,EAChE,eAAiB,GAAQ,EAAK,eAAe,CAAG,EAChD,cAAgB,GAAQ,EAAK,cAAc,CAAG,EAC9C,gBAAkB,GAAa,EAAK,gBAAgB,CAAQ,EAC5D,eAAgB,EAAQ,IAAQ,EAAK,cAAc,EAAQ,CAAG,EAC9D,QAAS,EAAuB,IAAQ,EAAK,OAAO,EAAuB,CAAG,EAC9E,YAAc,GAAQ,EAAK,YAAY,CAAG,EAC1C,eAAiB,GAAQ,EAAK,eAAe,CAAG,EAChD,eAAiB,GAAQ,EAAK,eAAe,CAAG,EAChD,cAAgB,GAAQ,EAAK,cAAc,CAAG,EAC9C,aAAe,GAAQ,EAAK,aAAa,CAAG,EAC5C,YAAc,GAAQ,EAAK,YAAY,CAAG,EAC1C,aAAe,GAAQ,EAAK,aAAa,CAAG,EAC5C,wBAA0B,GAAQ,EAAK,wBAAwB,CAAG,EAClE,QAAS,KAAO,IAAS,MAAM,EAAK,QAAQ,CAAG,GAAM,IAAI,EAAA,aAAa,YAAa,CAAE,OAAQ,GAAI,CAAC,CACnG,CACD"}