azirid-react 0.14.3 → 0.14.4
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/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/dist/next-proxy.cjs +32 -9
- package/dist/next-proxy.cjs.map +1 -1
- package/dist/next-proxy.d.cts +5 -4
- package/dist/next-proxy.d.ts +5 -4
- package/dist/next-proxy.js +33 -10
- package/dist/next-proxy.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
package/dist/index.js
CHANGED
|
@@ -4851,7 +4851,7 @@ function usePasswordToggle() {
|
|
|
4851
4851
|
}
|
|
4852
4852
|
|
|
4853
4853
|
// src/index.ts
|
|
4854
|
-
var SDK_VERSION = "0.14.
|
|
4854
|
+
var SDK_VERSION = "0.14.4";
|
|
4855
4855
|
|
|
4856
4856
|
export { AUTH_BASE_PATH, AuthForm, AziridProvider, CheckoutButton, ForgotPasswordForm, HandoffCallback, InvoiceList, LoginForm, PATHS, PayButton, PayphoneCallback, PayphoneWidgetRenderer, PricingTable, ReferralCard, ReferralStats, ResetPasswordForm, SDK_VERSION, SignupForm, SubscriptionBadge, buildPaths, changePasswordSchema, cn, createAccessClient, createForgotPasswordSchema, createLoginSchema, createMutationHook, createResetPasswordConfirmSchema, createSignupSchema, en, es, forgotPasswordSchema, isAuthError, loginSchema, magicLinkRequestSchema, magicLinkVerifySchema, passkeyRegisterStartSchema, removeStyles, resetPasswordConfirmSchema, resolveMessages, signupSchema, socialLoginSchema, useAccessClient, useAzirid, useBootstrap, useBranches, useBranding, useChangePassword, useCheckout, useFormState, useInvoices, useLogin, useLogout, useMagicLink, useMessages, usePasskeys, usePasswordReset, usePasswordToggle, usePayButton, usePaymentMethods, usePaymentProviders, usePayphoneCheckout, usePayphoneConfirm, usePlans, useReferral, useReferralStats, useRefresh, useSession, useSignup, useSocialLogin, useSubmitTransferProof, useSubscription, useSwitchTenant, useTenantMembers, useTenants, useTransferPayment, useTransferProofs, useUploadTransferProof };
|
|
4857
4857
|
//# sourceMappingURL=index.js.map
|
package/dist/next-proxy.cjs
CHANGED
|
@@ -4,16 +4,34 @@ var server = require('next/server');
|
|
|
4
4
|
var jose = require('jose');
|
|
5
5
|
|
|
6
6
|
// src/next-proxy.ts
|
|
7
|
-
var
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
7
|
+
var keyCache = /* @__PURE__ */ new Map();
|
|
8
|
+
var CACHE_TTL = 5 * 60 * 1e3;
|
|
9
|
+
function extractKid(token) {
|
|
10
|
+
try {
|
|
11
|
+
const headerB64 = token.split(".")[0];
|
|
12
|
+
const header = JSON.parse(
|
|
13
|
+
typeof Buffer !== "undefined" ? Buffer.from(headerB64, "base64url").toString() : atob(headerB64.replace(/-/g, "+").replace(/_/g, "/"))
|
|
14
|
+
);
|
|
15
|
+
return header.kid ?? null;
|
|
16
|
+
} catch {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
async function resolveKey(kid, apiUrl) {
|
|
21
|
+
const cached = keyCache.get(kid);
|
|
22
|
+
if (cached && Date.now() - cached.cachedAt < CACHE_TTL) return cached.key;
|
|
23
|
+
const res = await fetch(`${apiUrl}/v1/.well-known/jwks/${kid}.json`);
|
|
24
|
+
if (!res.ok) throw new Error(`JWKS fetch failed: ${res.status}`);
|
|
25
|
+
const { keys } = await res.json();
|
|
26
|
+
if (!keys?.length) throw new Error(`No key found for kid: ${kid}`);
|
|
27
|
+
const key = await jose.importJWK(keys[0], "RS256");
|
|
28
|
+
keyCache.set(kid, { key, cachedAt: Date.now() });
|
|
29
|
+
return key;
|
|
13
30
|
}
|
|
14
31
|
function createRequestInterceptor(options) {
|
|
15
32
|
const cookieName = options?.cookieName ?? "__session";
|
|
16
33
|
const loginUrl = options?.loginUrl ?? "/login";
|
|
34
|
+
const apiUrl = (options?.apiUrl ?? process.env.AZIRID_API_URL ?? "https://api.azirid.com").replace(/\/$/, "");
|
|
17
35
|
const defaultPublic = ["/login", "/signup", "/auth/handoff"];
|
|
18
36
|
const publicRoutes = options?.publicRoutes ? [.../* @__PURE__ */ new Set([...options.publicRoutes, "/auth/handoff"])] : defaultPublic;
|
|
19
37
|
const protectedRoutes = options?.protectedRoutes;
|
|
@@ -23,13 +41,18 @@ function createRequestInterceptor(options) {
|
|
|
23
41
|
const response = server.NextResponse.next();
|
|
24
42
|
if (token) {
|
|
25
43
|
try {
|
|
26
|
-
const
|
|
27
|
-
|
|
44
|
+
const kid = extractKid(token);
|
|
45
|
+
if (!kid) throw new Error("JWT missing kid");
|
|
46
|
+
const key = await resolveKey(kid, apiUrl);
|
|
47
|
+
const { payload } = await jose.jwtVerify(token, key);
|
|
28
48
|
response.headers.set("x-azirid-token", token);
|
|
29
49
|
if (payload.sub) response.headers.set("x-azirid-user-id", payload.sub);
|
|
30
50
|
} catch (err) {
|
|
31
51
|
if (typeof console !== "undefined") {
|
|
32
|
-
console.warn(
|
|
52
|
+
console.warn(
|
|
53
|
+
"[azirid-proxy] JWT validation failed:",
|
|
54
|
+
err instanceof Error ? err.message : err
|
|
55
|
+
);
|
|
33
56
|
}
|
|
34
57
|
response.headers.set("Set-Cookie", `${cookieName}=; Path=/; Max-Age=0; SameSite=Lax`);
|
|
35
58
|
}
|
package/dist/next-proxy.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/next-proxy.ts"],"names":["
|
|
1
|
+
{"version":3,"sources":["../src/next-proxy.ts"],"names":["importJWK","NextResponse","jwtVerify"],"mappings":"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","file":"next-proxy.cjs","sourcesContent":["/**\n * Next.js middleware for Azirid Access.\n *\n * Validates the `__session` JWT cookie by resolving the signing key\n * via the kid in the JWT header. Provides route protection and token\n * forwarding for server components.\n *\n * @example Next.js 16+ (proxy.ts)\n * ```ts\n * // proxy.ts\n * export { aziridProxy as proxy } from \"azirid-react/next/proxy\";\n * export const config = { matcher: [\"/((?!_next|favicon.ico|api/).*)\"] };\n * ```\n *\n * @example Next.js 16+ with custom options\n * ```ts\n * // proxy.ts\n * import { createAziridProxy } from \"azirid-react/next/proxy\";\n * export const proxy = createAziridProxy({\n * protectedRoutes: [\"/dashboard\"],\n * loginUrl: \"/login\",\n * });\n * export const config = { matcher: [\"/((?!_next|favicon.ico|api/).*)\"] };\n * ```\n *\n * @packageDocumentation\n */\n\nimport { NextResponse, type NextRequest } from 'next/server'\nimport { importJWK, jwtVerify, type JWK } from 'jose'\n\n// ─── Options ────────────────────────────────────────────────\n\nexport interface AziridProxyOptions {\n /** Cookie name that carries the access token JWT (default: \"__session\") */\n cookieName?: string\n /** Routes that require authentication (matched via startsWith) */\n protectedRoutes?: string[]\n /** Route to redirect to when not authenticated (default: \"/login\") */\n loginUrl?: string\n /** Routes that are always public (default: [\"/login\", \"/signup\"]) */\n publicRoutes?: string[]\n /** Override the Azirid API URL for key resolution (default: https://api.azirid.com) */\n apiUrl?: string\n}\n\n// ─── Key resolver (cached, resolves by kid) ─────────────────\n\nconst keyCache = new Map<string, { key: CryptoKey; cachedAt: number }>()\nconst CACHE_TTL = 5 * 60 * 1000 // 5 minutes\n\nfunction extractKid(token: string): string | null {\n try {\n const headerB64 = token.split('.')[0]\n const header = JSON.parse(\n typeof Buffer !== 'undefined'\n ? Buffer.from(headerB64, 'base64url').toString()\n : atob(headerB64.replace(/-/g, '+').replace(/_/g, '/')),\n )\n return header.kid ?? null\n } catch {\n return null\n }\n}\n\nasync function resolveKey(kid: string, apiUrl: string): Promise<CryptoKey> {\n const cached = keyCache.get(kid)\n if (cached && Date.now() - cached.cachedAt < CACHE_TTL) return cached.key\n\n const res = await fetch(`${apiUrl}/v1/.well-known/jwks/${kid}.json`)\n if (!res.ok) throw new Error(`JWKS fetch failed: ${res.status}`)\n\n const { keys } = (await res.json()) as { keys: JWK[] }\n if (!keys?.length) throw new Error(`No key found for kid: ${kid}`)\n\n const key = (await importJWK(keys[0], 'RS256')) as CryptoKey\n keyCache.set(kid, { key, cachedAt: Date.now() })\n return key\n}\n\n// ─── Middleware logic ───────────────────────────────────────\n\nfunction createRequestInterceptor(options?: AziridProxyOptions) {\n const cookieName = options?.cookieName ?? '__session'\n const loginUrl = options?.loginUrl ?? '/login'\n const apiUrl = (\n options?.apiUrl ??\n process.env.AZIRID_API_URL ??\n 'https://api.azirid.com'\n ).replace(/\\/$/, '')\n const defaultPublic = ['/login', '/signup', '/auth/handoff']\n const publicRoutes = options?.publicRoutes\n ? [...new Set([...options.publicRoutes, '/auth/handoff'])]\n : defaultPublic\n const protectedRoutes = options?.protectedRoutes\n\n return async function handler(request: NextRequest) {\n const { pathname } = request.nextUrl\n const token = request.cookies.get(cookieName)?.value\n\n const response = NextResponse.next()\n\n if (token) {\n try {\n const kid = extractKid(token)\n if (!kid) throw new Error('JWT missing kid')\n\n const key = await resolveKey(kid, apiUrl)\n const { payload } = await jwtVerify(token, key)\n\n // Valid token — expose for server components via headers\n response.headers.set('x-azirid-token', token)\n if (payload.sub) response.headers.set('x-azirid-user-id', payload.sub)\n } catch (err) {\n // Invalid or expired JWT — clear corrupted cookie\n if (typeof console !== 'undefined') {\n console.warn(\n '[azirid-proxy] JWT validation failed:',\n err instanceof Error ? err.message : err,\n )\n }\n response.headers.set('Set-Cookie', `${cookieName}=; Path=/; Max-Age=0; SameSite=Lax`)\n }\n }\n\n // Route protection (only when protectedRoutes is configured)\n if (protectedRoutes) {\n const hasValidToken = response.headers.has('x-azirid-token')\n const isPublic = publicRoutes.some((r) => pathname.startsWith(r))\n const isProtected = protectedRoutes.some((r) => pathname.startsWith(r))\n\n if (isProtected && !isPublic && !hasValidToken) {\n const url = request.nextUrl.clone()\n url.pathname = loginUrl\n url.searchParams.set('redirect', pathname)\n return NextResponse.redirect(url)\n }\n }\n\n return response\n }\n}\n\n// ─── Proxy (Next.js 16+) ────────────────────────────────────\n\n/**\n * Create a customized Azirid middleware for Next.js 16+.\n *\n * @example Default (one line)\n * ```ts\n * // proxy.ts\n * export { aziridProxy as proxy } from \"azirid-react/next/proxy\";\n * export const config = { matcher: [\"/((?!_next|favicon.ico|api/).*)\"] };\n * ```\n *\n * @example Custom options\n * ```ts\n * // proxy.ts\n * import { createAziridProxy } from \"azirid-react/next/proxy\";\n * export const proxy = createAziridProxy({\n * protectedRoutes: [\"/dashboard\"],\n * loginUrl: \"/login\",\n * });\n * export const config = { matcher: [\"/((?!_next|favicon.ico|api/).*)\"] };\n * ```\n */\nexport function createAziridProxy(options?: AziridProxyOptions) {\n return createRequestInterceptor(options)\n}\n\n/** Default proxy export for Next.js 16+ (no route protection, only validates + forwards token) */\nexport const aziridProxy = createAziridProxy()\n"]}
|
package/dist/next-proxy.d.cts
CHANGED
|
@@ -3,8 +3,9 @@ import { NextRequest, NextResponse } from 'next/server';
|
|
|
3
3
|
/**
|
|
4
4
|
* Next.js middleware for Azirid Access.
|
|
5
5
|
*
|
|
6
|
-
* Validates the `__session` JWT cookie
|
|
7
|
-
* route protection and token
|
|
6
|
+
* Validates the `__session` JWT cookie by resolving the signing key
|
|
7
|
+
* via the kid in the JWT header. Provides route protection and token
|
|
8
|
+
* forwarding for server components.
|
|
8
9
|
*
|
|
9
10
|
* @example Next.js 16+ (proxy.ts)
|
|
10
11
|
* ```ts
|
|
@@ -36,8 +37,8 @@ interface AziridProxyOptions {
|
|
|
36
37
|
loginUrl?: string;
|
|
37
38
|
/** Routes that are always public (default: ["/login", "/signup"]) */
|
|
38
39
|
publicRoutes?: string[];
|
|
39
|
-
/**
|
|
40
|
-
|
|
40
|
+
/** Override the Azirid API URL for key resolution (default: https://api.azirid.com) */
|
|
41
|
+
apiUrl?: string;
|
|
41
42
|
}
|
|
42
43
|
/**
|
|
43
44
|
* Create a customized Azirid middleware for Next.js 16+.
|
package/dist/next-proxy.d.ts
CHANGED
|
@@ -3,8 +3,9 @@ import { NextRequest, NextResponse } from 'next/server';
|
|
|
3
3
|
/**
|
|
4
4
|
* Next.js middleware for Azirid Access.
|
|
5
5
|
*
|
|
6
|
-
* Validates the `__session` JWT cookie
|
|
7
|
-
* route protection and token
|
|
6
|
+
* Validates the `__session` JWT cookie by resolving the signing key
|
|
7
|
+
* via the kid in the JWT header. Provides route protection and token
|
|
8
|
+
* forwarding for server components.
|
|
8
9
|
*
|
|
9
10
|
* @example Next.js 16+ (proxy.ts)
|
|
10
11
|
* ```ts
|
|
@@ -36,8 +37,8 @@ interface AziridProxyOptions {
|
|
|
36
37
|
loginUrl?: string;
|
|
37
38
|
/** Routes that are always public (default: ["/login", "/signup"]) */
|
|
38
39
|
publicRoutes?: string[];
|
|
39
|
-
/**
|
|
40
|
-
|
|
40
|
+
/** Override the Azirid API URL for key resolution (default: https://api.azirid.com) */
|
|
41
|
+
apiUrl?: string;
|
|
41
42
|
}
|
|
42
43
|
/**
|
|
43
44
|
* Create a customized Azirid middleware for Next.js 16+.
|
package/dist/next-proxy.js
CHANGED
|
@@ -1,17 +1,35 @@
|
|
|
1
1
|
import { NextResponse } from 'next/server';
|
|
2
|
-
import { jwtVerify,
|
|
2
|
+
import { jwtVerify, importJWK } from 'jose';
|
|
3
3
|
|
|
4
4
|
// src/next-proxy.ts
|
|
5
|
-
var
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
5
|
+
var keyCache = /* @__PURE__ */ new Map();
|
|
6
|
+
var CACHE_TTL = 5 * 60 * 1e3;
|
|
7
|
+
function extractKid(token) {
|
|
8
|
+
try {
|
|
9
|
+
const headerB64 = token.split(".")[0];
|
|
10
|
+
const header = JSON.parse(
|
|
11
|
+
typeof Buffer !== "undefined" ? Buffer.from(headerB64, "base64url").toString() : atob(headerB64.replace(/-/g, "+").replace(/_/g, "/"))
|
|
12
|
+
);
|
|
13
|
+
return header.kid ?? null;
|
|
14
|
+
} catch {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
async function resolveKey(kid, apiUrl) {
|
|
19
|
+
const cached = keyCache.get(kid);
|
|
20
|
+
if (cached && Date.now() - cached.cachedAt < CACHE_TTL) return cached.key;
|
|
21
|
+
const res = await fetch(`${apiUrl}/v1/.well-known/jwks/${kid}.json`);
|
|
22
|
+
if (!res.ok) throw new Error(`JWKS fetch failed: ${res.status}`);
|
|
23
|
+
const { keys } = await res.json();
|
|
24
|
+
if (!keys?.length) throw new Error(`No key found for kid: ${kid}`);
|
|
25
|
+
const key = await importJWK(keys[0], "RS256");
|
|
26
|
+
keyCache.set(kid, { key, cachedAt: Date.now() });
|
|
27
|
+
return key;
|
|
11
28
|
}
|
|
12
29
|
function createRequestInterceptor(options) {
|
|
13
30
|
const cookieName = options?.cookieName ?? "__session";
|
|
14
31
|
const loginUrl = options?.loginUrl ?? "/login";
|
|
32
|
+
const apiUrl = (options?.apiUrl ?? process.env.AZIRID_API_URL ?? "https://api.azirid.com").replace(/\/$/, "");
|
|
15
33
|
const defaultPublic = ["/login", "/signup", "/auth/handoff"];
|
|
16
34
|
const publicRoutes = options?.publicRoutes ? [.../* @__PURE__ */ new Set([...options.publicRoutes, "/auth/handoff"])] : defaultPublic;
|
|
17
35
|
const protectedRoutes = options?.protectedRoutes;
|
|
@@ -21,13 +39,18 @@ function createRequestInterceptor(options) {
|
|
|
21
39
|
const response = NextResponse.next();
|
|
22
40
|
if (token) {
|
|
23
41
|
try {
|
|
24
|
-
const
|
|
25
|
-
|
|
42
|
+
const kid = extractKid(token);
|
|
43
|
+
if (!kid) throw new Error("JWT missing kid");
|
|
44
|
+
const key = await resolveKey(kid, apiUrl);
|
|
45
|
+
const { payload } = await jwtVerify(token, key);
|
|
26
46
|
response.headers.set("x-azirid-token", token);
|
|
27
47
|
if (payload.sub) response.headers.set("x-azirid-user-id", payload.sub);
|
|
28
48
|
} catch (err) {
|
|
29
49
|
if (typeof console !== "undefined") {
|
|
30
|
-
console.warn(
|
|
50
|
+
console.warn(
|
|
51
|
+
"[azirid-proxy] JWT validation failed:",
|
|
52
|
+
err instanceof Error ? err.message : err
|
|
53
|
+
);
|
|
31
54
|
}
|
|
32
55
|
response.headers.set("Set-Cookie", `${cookieName}=; Path=/; Max-Age=0; SameSite=Lax`);
|
|
33
56
|
}
|
package/dist/next-proxy.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/next-proxy.ts"],"names":[],"mappings":";;;;
|
|
1
|
+
{"version":3,"sources":["../src/next-proxy.ts"],"names":[],"mappings":"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","file":"next-proxy.js","sourcesContent":["/**\n * Next.js middleware for Azirid Access.\n *\n * Validates the `__session` JWT cookie by resolving the signing key\n * via the kid in the JWT header. Provides route protection and token\n * forwarding for server components.\n *\n * @example Next.js 16+ (proxy.ts)\n * ```ts\n * // proxy.ts\n * export { aziridProxy as proxy } from \"azirid-react/next/proxy\";\n * export const config = { matcher: [\"/((?!_next|favicon.ico|api/).*)\"] };\n * ```\n *\n * @example Next.js 16+ with custom options\n * ```ts\n * // proxy.ts\n * import { createAziridProxy } from \"azirid-react/next/proxy\";\n * export const proxy = createAziridProxy({\n * protectedRoutes: [\"/dashboard\"],\n * loginUrl: \"/login\",\n * });\n * export const config = { matcher: [\"/((?!_next|favicon.ico|api/).*)\"] };\n * ```\n *\n * @packageDocumentation\n */\n\nimport { NextResponse, type NextRequest } from 'next/server'\nimport { importJWK, jwtVerify, type JWK } from 'jose'\n\n// ─── Options ────────────────────────────────────────────────\n\nexport interface AziridProxyOptions {\n /** Cookie name that carries the access token JWT (default: \"__session\") */\n cookieName?: string\n /** Routes that require authentication (matched via startsWith) */\n protectedRoutes?: string[]\n /** Route to redirect to when not authenticated (default: \"/login\") */\n loginUrl?: string\n /** Routes that are always public (default: [\"/login\", \"/signup\"]) */\n publicRoutes?: string[]\n /** Override the Azirid API URL for key resolution (default: https://api.azirid.com) */\n apiUrl?: string\n}\n\n// ─── Key resolver (cached, resolves by kid) ─────────────────\n\nconst keyCache = new Map<string, { key: CryptoKey; cachedAt: number }>()\nconst CACHE_TTL = 5 * 60 * 1000 // 5 minutes\n\nfunction extractKid(token: string): string | null {\n try {\n const headerB64 = token.split('.')[0]\n const header = JSON.parse(\n typeof Buffer !== 'undefined'\n ? Buffer.from(headerB64, 'base64url').toString()\n : atob(headerB64.replace(/-/g, '+').replace(/_/g, '/')),\n )\n return header.kid ?? null\n } catch {\n return null\n }\n}\n\nasync function resolveKey(kid: string, apiUrl: string): Promise<CryptoKey> {\n const cached = keyCache.get(kid)\n if (cached && Date.now() - cached.cachedAt < CACHE_TTL) return cached.key\n\n const res = await fetch(`${apiUrl}/v1/.well-known/jwks/${kid}.json`)\n if (!res.ok) throw new Error(`JWKS fetch failed: ${res.status}`)\n\n const { keys } = (await res.json()) as { keys: JWK[] }\n if (!keys?.length) throw new Error(`No key found for kid: ${kid}`)\n\n const key = (await importJWK(keys[0], 'RS256')) as CryptoKey\n keyCache.set(kid, { key, cachedAt: Date.now() })\n return key\n}\n\n// ─── Middleware logic ───────────────────────────────────────\n\nfunction createRequestInterceptor(options?: AziridProxyOptions) {\n const cookieName = options?.cookieName ?? '__session'\n const loginUrl = options?.loginUrl ?? '/login'\n const apiUrl = (\n options?.apiUrl ??\n process.env.AZIRID_API_URL ??\n 'https://api.azirid.com'\n ).replace(/\\/$/, '')\n const defaultPublic = ['/login', '/signup', '/auth/handoff']\n const publicRoutes = options?.publicRoutes\n ? [...new Set([...options.publicRoutes, '/auth/handoff'])]\n : defaultPublic\n const protectedRoutes = options?.protectedRoutes\n\n return async function handler(request: NextRequest) {\n const { pathname } = request.nextUrl\n const token = request.cookies.get(cookieName)?.value\n\n const response = NextResponse.next()\n\n if (token) {\n try {\n const kid = extractKid(token)\n if (!kid) throw new Error('JWT missing kid')\n\n const key = await resolveKey(kid, apiUrl)\n const { payload } = await jwtVerify(token, key)\n\n // Valid token — expose for server components via headers\n response.headers.set('x-azirid-token', token)\n if (payload.sub) response.headers.set('x-azirid-user-id', payload.sub)\n } catch (err) {\n // Invalid or expired JWT — clear corrupted cookie\n if (typeof console !== 'undefined') {\n console.warn(\n '[azirid-proxy] JWT validation failed:',\n err instanceof Error ? err.message : err,\n )\n }\n response.headers.set('Set-Cookie', `${cookieName}=; Path=/; Max-Age=0; SameSite=Lax`)\n }\n }\n\n // Route protection (only when protectedRoutes is configured)\n if (protectedRoutes) {\n const hasValidToken = response.headers.has('x-azirid-token')\n const isPublic = publicRoutes.some((r) => pathname.startsWith(r))\n const isProtected = protectedRoutes.some((r) => pathname.startsWith(r))\n\n if (isProtected && !isPublic && !hasValidToken) {\n const url = request.nextUrl.clone()\n url.pathname = loginUrl\n url.searchParams.set('redirect', pathname)\n return NextResponse.redirect(url)\n }\n }\n\n return response\n }\n}\n\n// ─── Proxy (Next.js 16+) ────────────────────────────────────\n\n/**\n * Create a customized Azirid middleware for Next.js 16+.\n *\n * @example Default (one line)\n * ```ts\n * // proxy.ts\n * export { aziridProxy as proxy } from \"azirid-react/next/proxy\";\n * export const config = { matcher: [\"/((?!_next|favicon.ico|api/).*)\"] };\n * ```\n *\n * @example Custom options\n * ```ts\n * // proxy.ts\n * import { createAziridProxy } from \"azirid-react/next/proxy\";\n * export const proxy = createAziridProxy({\n * protectedRoutes: [\"/dashboard\"],\n * loginUrl: \"/login\",\n * });\n * export const config = { matcher: [\"/((?!_next|favicon.ico|api/).*)\"] };\n * ```\n */\nexport function createAziridProxy(options?: AziridProxyOptions) {\n return createRequestInterceptor(options)\n}\n\n/** Default proxy export for Next.js 16+ (no route protection, only validates + forwards token) */\nexport const aziridProxy = createAziridProxy()\n"]}
|