@bounc.ing/next 0.1.0 → 0.2.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/dist/client/provider.d.ts +1 -0
- package/dist/client/provider.js +19 -5
- package/dist/client/use-user.d.ts +1 -0
- package/dist/client/use-user.js +2 -2
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/server/auth.d.ts +2 -0
- package/dist/server/auth.js +15 -4
- package/dist/types.d.ts +11 -0
- package/dist/types.js +21 -1
- package/package.json +2 -2
package/dist/client/provider.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
3
|
import { createContext, useContext, useState, useEffect } from 'react';
|
|
4
4
|
const BouncingContext = createContext({
|
|
5
|
-
user: null, isLoading: true, domain: '',
|
|
5
|
+
user: null, isLoading: true, error: null, domain: '',
|
|
6
6
|
});
|
|
7
7
|
export function useBouncingContext() {
|
|
8
8
|
return useContext(BouncingContext);
|
|
@@ -10,6 +10,7 @@ export function useBouncingContext() {
|
|
|
10
10
|
export function BouncingProvider({ domain, children }) {
|
|
11
11
|
const [user, setUser] = useState(null);
|
|
12
12
|
const [isLoading, setIsLoading] = useState(true);
|
|
13
|
+
const [error, setError] = useState(null);
|
|
13
14
|
useEffect(() => {
|
|
14
15
|
// Try hydration from server-rendered script tag
|
|
15
16
|
const script = document.getElementById('__bouncing');
|
|
@@ -26,10 +27,23 @@ export function BouncingProvider({ domain, children }) {
|
|
|
26
27
|
}
|
|
27
28
|
// Fetch from /auth/me
|
|
28
29
|
fetch(`https://${domain}/auth/me`, { credentials: 'include' })
|
|
29
|
-
.then((res) =>
|
|
30
|
-
.
|
|
31
|
-
|
|
30
|
+
.then(async (res) => {
|
|
31
|
+
if (res.status === 401) {
|
|
32
|
+
// Not authenticated — not an error, just no user
|
|
33
|
+
setUser(null);
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
if (!res.ok) {
|
|
37
|
+
throw new Error(`/auth/me returned ${res.status}`);
|
|
38
|
+
}
|
|
39
|
+
const data = await res.json();
|
|
40
|
+
setUser(data);
|
|
41
|
+
})
|
|
42
|
+
.catch((e) => {
|
|
43
|
+
setError(e instanceof Error ? e : new Error(String(e)));
|
|
44
|
+
setUser(null);
|
|
45
|
+
})
|
|
32
46
|
.finally(() => setIsLoading(false));
|
|
33
47
|
}, [domain]);
|
|
34
|
-
return (_jsx(BouncingContext, { value: { user, isLoading, domain }, children: children }));
|
|
48
|
+
return (_jsx(BouncingContext, { value: { user, isLoading, error, domain }, children: children }));
|
|
35
49
|
}
|
package/dist/client/use-user.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { useBouncingContext } from './provider.js';
|
|
3
3
|
export function useUser() {
|
|
4
|
-
const { user, isLoading } = useBouncingContext();
|
|
5
|
-
return { user, isLoading };
|
|
4
|
+
const { user, isLoading, error } = useBouncingContext();
|
|
5
|
+
return { user, isLoading, error };
|
|
6
6
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -2,3 +2,4 @@ export { createBouncing } from './server/config.js';
|
|
|
2
2
|
export type { BouncingConfig, BouncingInstance, Session, User } from './server/config.js';
|
|
3
3
|
export { createAdminClient } from './server/admin.js';
|
|
4
4
|
export type { BouncingAdminClient } from './server/admin.js';
|
|
5
|
+
export { BouncingError, BouncingUnauthenticatedError, BouncingNetworkError } from './types.js';
|
package/dist/index.js
CHANGED
package/dist/server/auth.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { Session } from '../types.js';
|
|
2
|
+
/** Clear the JWKS cache for a baseURL — call after verification failure to force re-fetch */
|
|
3
|
+
export declare function invalidateJWKSCache(baseURL: string): void;
|
|
2
4
|
/** Verify a JWT access token against the JWKS endpoint. Returns Session or null. */
|
|
3
5
|
export declare function verifyAccessToken(token: string, baseURL: string): Promise<Session | null>;
|
|
4
6
|
/** Exchange a refresh token for new tokens. Returns null on failure. */
|
package/dist/server/auth.js
CHANGED
|
@@ -1,13 +1,22 @@
|
|
|
1
1
|
import { createRemoteJWKSet, jwtVerify } from 'jose';
|
|
2
|
+
const JWKS_TTL_MS = 60 * 60 * 1000; // 1 hour
|
|
2
3
|
const jwksCache = new Map();
|
|
3
4
|
function getJWKS(baseURL) {
|
|
4
|
-
|
|
5
|
-
if (
|
|
6
|
-
|
|
7
|
-
jwksCache.set(baseURL, jwks);
|
|
5
|
+
const cached = jwksCache.get(baseURL);
|
|
6
|
+
if (cached && Date.now() - cached.fetchedAt < JWKS_TTL_MS) {
|
|
7
|
+
return cached.jwks;
|
|
8
8
|
}
|
|
9
|
+
const jwks = createRemoteJWKSet(new URL('/.well-known/jwks.json', baseURL), {
|
|
10
|
+
cacheMaxAge: JWKS_TTL_MS,
|
|
11
|
+
cooldownDuration: 5000,
|
|
12
|
+
});
|
|
13
|
+
jwksCache.set(baseURL, { jwks, fetchedAt: Date.now() });
|
|
9
14
|
return jwks;
|
|
10
15
|
}
|
|
16
|
+
/** Clear the JWKS cache for a baseURL — call after verification failure to force re-fetch */
|
|
17
|
+
export function invalidateJWKSCache(baseURL) {
|
|
18
|
+
jwksCache.delete(baseURL);
|
|
19
|
+
}
|
|
11
20
|
/** Verify a JWT access token against the JWKS endpoint. Returns Session or null. */
|
|
12
21
|
export async function verifyAccessToken(token, baseURL) {
|
|
13
22
|
try {
|
|
@@ -28,6 +37,8 @@ export async function verifyAccessToken(token, baseURL) {
|
|
|
28
37
|
};
|
|
29
38
|
}
|
|
30
39
|
catch {
|
|
40
|
+
// Invalidate cache on verification failure — signing keys may have rotated
|
|
41
|
+
invalidateJWKSCache(baseURL);
|
|
31
42
|
return null;
|
|
32
43
|
}
|
|
33
44
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -21,3 +21,14 @@ export interface TokenResponse {
|
|
|
21
21
|
refresh_token: string;
|
|
22
22
|
expires_in: number;
|
|
23
23
|
}
|
|
24
|
+
/** Base class for SDK errors */
|
|
25
|
+
export declare class BouncingError extends Error {
|
|
26
|
+
code: string;
|
|
27
|
+
constructor(message: string, code: string);
|
|
28
|
+
}
|
|
29
|
+
export declare class BouncingUnauthenticatedError extends BouncingError {
|
|
30
|
+
constructor(message?: string);
|
|
31
|
+
}
|
|
32
|
+
export declare class BouncingNetworkError extends BouncingError {
|
|
33
|
+
constructor(message: string);
|
|
34
|
+
}
|
package/dist/types.js
CHANGED
|
@@ -1 +1,21 @@
|
|
|
1
|
-
|
|
1
|
+
/** Base class for SDK errors */
|
|
2
|
+
export class BouncingError extends Error {
|
|
3
|
+
code;
|
|
4
|
+
constructor(message, code) {
|
|
5
|
+
super(message);
|
|
6
|
+
this.code = code;
|
|
7
|
+
this.name = 'BouncingError';
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
export class BouncingUnauthenticatedError extends BouncingError {
|
|
11
|
+
constructor(message = 'Not authenticated') {
|
|
12
|
+
super(message, 'unauthenticated');
|
|
13
|
+
this.name = 'BouncingUnauthenticatedError';
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export class BouncingNetworkError extends BouncingError {
|
|
17
|
+
constructor(message) {
|
|
18
|
+
super(message, 'network_error');
|
|
19
|
+
this.name = 'BouncingNetworkError';
|
|
20
|
+
}
|
|
21
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bounc.ing/next",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "Bouncing auth SDK for Next.js — auth for your app in 3 minutes",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"vitest": "^4.1.0"
|
|
39
39
|
},
|
|
40
40
|
"files": ["dist"],
|
|
41
|
-
"license": "
|
|
41
|
+
"license": "Apache-2.0",
|
|
42
42
|
"repository": {
|
|
43
43
|
"type": "git",
|
|
44
44
|
"url": "https://github.com/scttfrdmn/bouncing-managed",
|