azirid-react 0.13.2 → 0.14.1

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.
@@ -1,25 +1,41 @@
1
1
  'use strict';
2
2
 
3
3
  var server = require('next/server');
4
+ var jose = require('jose');
4
5
 
5
6
  // src/next-proxy.ts
7
+ var jwks = null;
8
+ function getJwks(jwksUrl) {
9
+ if (jwks) return jwks;
10
+ const url = jwksUrl ?? `${process.env.AZIRID_API_URL ?? "https://api.azirid.com"}/v1/.well-known/jwks.json`;
11
+ jwks = jose.createRemoteJWKSet(new URL(url));
12
+ return jwks;
13
+ }
6
14
  function createRequestInterceptor(options) {
7
15
  const cookieName = options?.cookieName ?? "__session";
8
16
  const loginUrl = options?.loginUrl ?? "/login";
9
17
  const defaultPublic = ["/login", "/signup", "/auth/handoff"];
10
18
  const publicRoutes = options?.publicRoutes ? [.../* @__PURE__ */ new Set([...options.publicRoutes, "/auth/handoff"])] : defaultPublic;
11
19
  const protectedRoutes = options?.protectedRoutes;
12
- return function handler(request) {
20
+ return async function handler(request) {
13
21
  const { pathname } = request.nextUrl;
14
22
  const token = request.cookies.get(cookieName)?.value;
15
23
  const response = server.NextResponse.next();
16
24
  if (token) {
17
- response.headers.set("x-azirid-token", token);
25
+ try {
26
+ const keySet = getJwks(options?.jwksUrl);
27
+ const { payload } = await jose.jwtVerify(token, keySet);
28
+ response.headers.set("x-azirid-token", token);
29
+ if (payload.sub) response.headers.set("x-azirid-user-id", payload.sub);
30
+ } catch {
31
+ response.headers.set("Set-Cookie", `${cookieName}=; Path=/; Max-Age=0; SameSite=Lax`);
32
+ }
18
33
  }
19
34
  if (protectedRoutes) {
35
+ const hasValidToken = response.headers.has("x-azirid-token");
20
36
  const isPublic = publicRoutes.some((r) => pathname.startsWith(r));
21
37
  const isProtected = protectedRoutes.some((r) => pathname.startsWith(r));
22
- if (isProtected && !isPublic && !token) {
38
+ if (isProtected && !isPublic && !hasValidToken) {
23
39
  const url = request.nextUrl.clone();
24
40
  url.pathname = loginUrl;
25
41
  url.searchParams.set("redirect", pathname);
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/next-proxy.ts"],"names":["NextResponse"],"mappings":";;;;;AA0CA,SAAS,yBAAyB,OAAA,EAA8B;AAC9D,EAAA,MAAM,UAAA,GAAa,SAAS,UAAA,IAAc,WAAA;AAC1C,EAAA,MAAM,QAAA,GAAW,SAAS,QAAA,IAAY,QAAA;AACtC,EAAA,MAAM,aAAA,GAAgB,CAAC,QAAA,EAAU,SAAA,EAAW,eAAe,CAAA;AAC3D,EAAA,MAAM,YAAA,GAAe,OAAA,EAAS,YAAA,GAC1B,CAAC,mBAAG,IAAI,GAAA,CAAI,CAAC,GAAG,OAAA,CAAQ,YAAA,EAAc,eAAe,CAAC,CAAC,CAAA,GACvD,aAAA;AACJ,EAAA,MAAM,kBAAkB,OAAA,EAAS,eAAA;AAEjC,EAAA,OAAO,SAAS,QAAQ,OAAA,EAAsB;AAC5C,IAAA,MAAM,EAAE,QAAA,EAAS,GAAI,OAAA,CAAQ,OAAA;AAC7B,IAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,OAAA,CAAQ,GAAA,CAAI,UAAU,CAAA,EAAG,KAAA;AAE/C,IAAA,MAAM,QAAA,GAAWA,oBAAa,IAAA,EAAK;AAGnC,IAAA,IAAI,KAAA,EAAO;AACT,MAAA,QAAA,CAAS,OAAA,CAAQ,GAAA,CAAI,gBAAA,EAAkB,KAAK,CAAA;AAAA,IAC9C;AAGA,IAAA,IAAI,eAAA,EAAiB;AACnB,MAAA,MAAM,QAAA,GAAW,aAAa,IAAA,CAAK,CAAC,MAAM,QAAA,CAAS,UAAA,CAAW,CAAC,CAAC,CAAA;AAChE,MAAA,MAAM,WAAA,GAAc,gBAAgB,IAAA,CAAK,CAAC,MAAM,QAAA,CAAS,UAAA,CAAW,CAAC,CAAC,CAAA;AAEtE,MAAA,IAAI,WAAA,IAAe,CAAC,QAAA,IAAY,CAAC,KAAA,EAAO;AACtC,QAAA,MAAM,GAAA,GAAM,OAAA,CAAQ,OAAA,CAAQ,KAAA,EAAM;AAClC,QAAA,GAAA,CAAI,QAAA,GAAW,QAAA;AACf,QAAA,GAAA,CAAI,YAAA,CAAa,GAAA,CAAI,UAAA,EAAY,QAAQ,CAAA;AACzC,QAAA,OAAOA,mBAAA,CAAa,SAAS,GAAG,CAAA;AAAA,MAClC;AAAA,IACF;AAEA,IAAA,OAAO,QAAA;AAAA,EACT,CAAA;AACF;AAyBO,SAAS,kBAAkB,OAAA,EAA8B;AAC9D,EAAA,OAAO,yBAAyB,OAAO,CAAA;AACzC;AAGO,IAAM,cAAc,iBAAA","file":"next-proxy.cjs","sourcesContent":["/**\n * Next.js proxy and middleware utilities for Azirid Access.\n *\n * This entry point requires `next/server` and provides request interception\n * for route protection and token forwarding.\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({ protectedRoutes: [\"/dashboard\"] });\n * export const config = { matcher: [\"/((?!_next|favicon.ico|api/).*)\"] };\n * ```\n *\n * @packageDocumentation\n */\n\nimport { NextResponse, type NextRequest } from 'next/server'\n\n// ─── Proxy / Middleware Options ──────────────────────────────\n\nexport interface AziridProxyOptions {\n /** Cookie name (default: \"__session\") */\n cookieName?: string\n /** Routes that require authentication (glob patterns 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}\n\n\n// ─── Shared proxy/middleware logic ───────────────────────────\n\nfunction createRequestInterceptor(options?: AziridProxyOptions) {\n const cookieName = options?.cookieName ?? '__session'\n const loginUrl = options?.loginUrl ?? '/login'\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 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 // Expose token as internal header for server components\n if (token) {\n response.headers.set('x-azirid-token', token)\n }\n\n // Route protection (only when protectedRoutes is configured)\n if (protectedRoutes) {\n const isPublic = publicRoutes.some((r) => pathname.startsWith(r))\n const isProtected = protectedRoutes.some((r) => pathname.startsWith(r))\n\n if (isProtected && !isPublic && !token) {\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 proxy for Next.js 16+.\n *\n * In Next.js 16, `middleware.ts` is renamed to `proxy.ts` and the\n * exported function must be named `proxy`.\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({ protectedRoutes: [\"/dashboard\"] });\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 forwards token) */\nexport const aziridProxy = createAziridProxy()\n\n"]}
1
+ {"version":3,"sources":["../src/next-proxy.ts"],"names":["createRemoteJWKSet","NextResponse","jwtVerify"],"mappings":";;;;;;AA+CA,IAAI,IAAA,GAAqD,IAAA;AAEzD,SAAS,QAAQ,OAAA,EAAyD;AACxE,EAAA,IAAI,MAAM,OAAO,IAAA;AACjB,EAAA,MAAM,MACJ,OAAA,IACA,CAAA,EAAG,OAAA,CAAQ,GAAA,CAAI,kBAAkB,wBAAwB,CAAA,yBAAA,CAAA;AAC3D,EAAA,IAAA,GAAOA,uBAAA,CAAmB,IAAI,GAAA,CAAI,GAAG,CAAC,CAAA;AACtC,EAAA,OAAO,IAAA;AACT;AAIA,SAAS,yBAAyB,OAAA,EAA8B;AAC9D,EAAA,MAAM,UAAA,GAAa,SAAS,UAAA,IAAc,WAAA;AAC1C,EAAA,MAAM,QAAA,GAAW,SAAS,QAAA,IAAY,QAAA;AACtC,EAAA,MAAM,aAAA,GAAgB,CAAC,QAAA,EAAU,SAAA,EAAW,eAAe,CAAA;AAC3D,EAAA,MAAM,YAAA,GAAe,OAAA,EAAS,YAAA,GAC1B,CAAC,mBAAG,IAAI,GAAA,CAAI,CAAC,GAAG,OAAA,CAAQ,YAAA,EAAc,eAAe,CAAC,CAAC,CAAA,GACvD,aAAA;AACJ,EAAA,MAAM,kBAAkB,OAAA,EAAS,eAAA;AAEjC,EAAA,OAAO,eAAe,QAAQ,OAAA,EAAsB;AAClD,IAAA,MAAM,EAAE,QAAA,EAAS,GAAI,OAAA,CAAQ,OAAA;AAC7B,IAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,OAAA,CAAQ,GAAA,CAAI,UAAU,CAAA,EAAG,KAAA;AAE/C,IAAA,MAAM,QAAA,GAAWC,oBAAa,IAAA,EAAK;AAEnC,IAAA,IAAI,KAAA,EAAO;AACT,MAAA,IAAI;AACF,QAAA,MAAM,MAAA,GAAS,OAAA,CAAQ,OAAA,EAAS,OAAO,CAAA;AACvC,QAAA,MAAM,EAAE,OAAA,EAAQ,GAAI,MAAMC,cAAA,CAAU,OAAO,MAAM,CAAA;AAEjD,QAAA,QAAA,CAAS,OAAA,CAAQ,GAAA,CAAI,gBAAA,EAAkB,KAAK,CAAA;AAC5C,QAAA,IAAI,QAAQ,GAAA,EAAK,QAAA,CAAS,QAAQ,GAAA,CAAI,kBAAA,EAAoB,QAAQ,GAAG,CAAA;AAAA,MACvE,CAAA,CAAA,MAAQ;AAEN,QAAA,QAAA,CAAS,OAAA,CAAQ,GAAA,CAAI,YAAA,EAAc,CAAA,EAAG,UAAU,CAAA,kCAAA,CAAoC,CAAA;AAAA,MACtF;AAAA,IACF;AAGA,IAAA,IAAI,eAAA,EAAiB;AACnB,MAAA,MAAM,aAAA,GAAgB,QAAA,CAAS,OAAA,CAAQ,GAAA,CAAI,gBAAgB,CAAA;AAC3D,MAAA,MAAM,QAAA,GAAW,aAAa,IAAA,CAAK,CAAC,MAAM,QAAA,CAAS,UAAA,CAAW,CAAC,CAAC,CAAA;AAChE,MAAA,MAAM,WAAA,GAAc,gBAAgB,IAAA,CAAK,CAAC,MAAM,QAAA,CAAS,UAAA,CAAW,CAAC,CAAC,CAAA;AAEtE,MAAA,IAAI,WAAA,IAAe,CAAC,QAAA,IAAY,CAAC,aAAA,EAAe;AAC9C,QAAA,MAAM,GAAA,GAAM,OAAA,CAAQ,OAAA,CAAQ,KAAA,EAAM;AAClC,QAAA,GAAA,CAAI,QAAA,GAAW,QAAA;AACf,QAAA,GAAA,CAAI,YAAA,CAAa,GAAA,CAAI,UAAA,EAAY,QAAQ,CAAA;AACzC,QAAA,OAAOD,mBAAA,CAAa,SAAS,GAAG,CAAA;AAAA,MAClC;AAAA,IACF;AAEA,IAAA,OAAO,QAAA;AAAA,EACT,CAAA;AACF;AAyBO,SAAS,kBAAkB,OAAA,EAA8B;AAC9D,EAAA,OAAO,yBAAyB,OAAO,CAAA;AACzC;AAGO,IAAM,cAAc,iBAAA","file":"next-proxy.cjs","sourcesContent":["/**\n * Next.js middleware for Azirid Access.\n *\n * Validates the `__session` JWT cookie using JWKS and provides\n * route protection and token 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 { createRemoteJWKSet, jwtVerify } 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 /** JWKS endpoint URL. Default: `${AZIRID_API_URL}/v1/.well-known/jwks.json` */\n jwksUrl?: string\n}\n\n// ─── JWKS (lazy-initialized, cached by jose internally) ─────\n\nlet jwks: ReturnType<typeof createRemoteJWKSet> | null = null\n\nfunction getJwks(jwksUrl?: string): ReturnType<typeof createRemoteJWKSet> {\n if (jwks) return jwks\n const url =\n jwksUrl ??\n `${process.env.AZIRID_API_URL ?? 'https://api.azirid.com'}/v1/.well-known/jwks.json`\n jwks = createRemoteJWKSet(new URL(url))\n return jwks\n}\n\n// ─── Middleware logic ───────────────────────────────────────\n\nfunction createRequestInterceptor(options?: AziridProxyOptions) {\n const cookieName = options?.cookieName ?? '__session'\n const loginUrl = options?.loginUrl ?? '/login'\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 keySet = getJwks(options?.jwksUrl)\n const { payload } = await jwtVerify(token, keySet)\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 {\n // Invalid or expired JWT — clear corrupted cookie\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"]}
@@ -1,10 +1,10 @@
1
1
  import { NextRequest, NextResponse } from 'next/server';
2
2
 
3
3
  /**
4
- * Next.js proxy and middleware utilities for Azirid Access.
4
+ * Next.js middleware for Azirid Access.
5
5
  *
6
- * This entry point requires `next/server` and provides request interception
7
- * for route protection and token forwarding.
6
+ * Validates the `__session` JWT cookie using JWKS and provides
7
+ * route protection and token forwarding for server components.
8
8
  *
9
9
  * @example Next.js 16+ (proxy.ts)
10
10
  * ```ts
@@ -17,7 +17,10 @@ import { NextRequest, NextResponse } from 'next/server';
17
17
  * ```ts
18
18
  * // proxy.ts
19
19
  * import { createAziridProxy } from "azirid-react/next/proxy";
20
- * export const proxy = createAziridProxy({ protectedRoutes: ["/dashboard"] });
20
+ * export const proxy = createAziridProxy({
21
+ * protectedRoutes: ["/dashboard"],
22
+ * loginUrl: "/login",
23
+ * });
21
24
  * export const config = { matcher: ["/((?!_next|favicon.ico|api/).*)"] };
22
25
  * ```
23
26
  *
@@ -25,20 +28,19 @@ import { NextRequest, NextResponse } from 'next/server';
25
28
  */
26
29
 
27
30
  interface AziridProxyOptions {
28
- /** Cookie name (default: "__session") */
31
+ /** Cookie name that carries the access token JWT (default: "__session") */
29
32
  cookieName?: string;
30
- /** Routes that require authentication (glob patterns via startsWith) */
33
+ /** Routes that require authentication (matched via startsWith) */
31
34
  protectedRoutes?: string[];
32
35
  /** Route to redirect to when not authenticated (default: "/login") */
33
36
  loginUrl?: string;
34
37
  /** Routes that are always public (default: ["/login", "/signup"]) */
35
38
  publicRoutes?: string[];
39
+ /** JWKS endpoint URL. Default: `${AZIRID_API_URL}/v1/.well-known/jwks.json` */
40
+ jwksUrl?: string;
36
41
  }
37
42
  /**
38
- * Create a customized Azirid proxy for Next.js 16+.
39
- *
40
- * In Next.js 16, `middleware.ts` is renamed to `proxy.ts` and the
41
- * exported function must be named `proxy`.
43
+ * Create a customized Azirid middleware for Next.js 16+.
42
44
  *
43
45
  * @example Default (one line)
44
46
  * ```ts
@@ -51,12 +53,15 @@ interface AziridProxyOptions {
51
53
  * ```ts
52
54
  * // proxy.ts
53
55
  * import { createAziridProxy } from "azirid-react/next/proxy";
54
- * export const proxy = createAziridProxy({ protectedRoutes: ["/dashboard"] });
56
+ * export const proxy = createAziridProxy({
57
+ * protectedRoutes: ["/dashboard"],
58
+ * loginUrl: "/login",
59
+ * });
55
60
  * export const config = { matcher: ["/((?!_next|favicon.ico|api/).*)"] };
56
61
  * ```
57
62
  */
58
- declare function createAziridProxy(options?: AziridProxyOptions): (request: NextRequest) => NextResponse;
59
- /** Default proxy export for Next.js 16+ (no route protection, only forwards token) */
60
- declare const aziridProxy: (request: NextRequest) => NextResponse;
63
+ declare function createAziridProxy(options?: AziridProxyOptions): (request: NextRequest) => Promise<NextResponse>;
64
+ /** Default proxy export for Next.js 16+ (no route protection, only validates + forwards token) */
65
+ declare const aziridProxy: (request: NextRequest) => Promise<NextResponse>;
61
66
 
62
67
  export { type AziridProxyOptions, aziridProxy, createAziridProxy };
@@ -1,10 +1,10 @@
1
1
  import { NextRequest, NextResponse } from 'next/server';
2
2
 
3
3
  /**
4
- * Next.js proxy and middleware utilities for Azirid Access.
4
+ * Next.js middleware for Azirid Access.
5
5
  *
6
- * This entry point requires `next/server` and provides request interception
7
- * for route protection and token forwarding.
6
+ * Validates the `__session` JWT cookie using JWKS and provides
7
+ * route protection and token forwarding for server components.
8
8
  *
9
9
  * @example Next.js 16+ (proxy.ts)
10
10
  * ```ts
@@ -17,7 +17,10 @@ import { NextRequest, NextResponse } from 'next/server';
17
17
  * ```ts
18
18
  * // proxy.ts
19
19
  * import { createAziridProxy } from "azirid-react/next/proxy";
20
- * export const proxy = createAziridProxy({ protectedRoutes: ["/dashboard"] });
20
+ * export const proxy = createAziridProxy({
21
+ * protectedRoutes: ["/dashboard"],
22
+ * loginUrl: "/login",
23
+ * });
21
24
  * export const config = { matcher: ["/((?!_next|favicon.ico|api/).*)"] };
22
25
  * ```
23
26
  *
@@ -25,20 +28,19 @@ import { NextRequest, NextResponse } from 'next/server';
25
28
  */
26
29
 
27
30
  interface AziridProxyOptions {
28
- /** Cookie name (default: "__session") */
31
+ /** Cookie name that carries the access token JWT (default: "__session") */
29
32
  cookieName?: string;
30
- /** Routes that require authentication (glob patterns via startsWith) */
33
+ /** Routes that require authentication (matched via startsWith) */
31
34
  protectedRoutes?: string[];
32
35
  /** Route to redirect to when not authenticated (default: "/login") */
33
36
  loginUrl?: string;
34
37
  /** Routes that are always public (default: ["/login", "/signup"]) */
35
38
  publicRoutes?: string[];
39
+ /** JWKS endpoint URL. Default: `${AZIRID_API_URL}/v1/.well-known/jwks.json` */
40
+ jwksUrl?: string;
36
41
  }
37
42
  /**
38
- * Create a customized Azirid proxy for Next.js 16+.
39
- *
40
- * In Next.js 16, `middleware.ts` is renamed to `proxy.ts` and the
41
- * exported function must be named `proxy`.
43
+ * Create a customized Azirid middleware for Next.js 16+.
42
44
  *
43
45
  * @example Default (one line)
44
46
  * ```ts
@@ -51,12 +53,15 @@ interface AziridProxyOptions {
51
53
  * ```ts
52
54
  * // proxy.ts
53
55
  * import { createAziridProxy } from "azirid-react/next/proxy";
54
- * export const proxy = createAziridProxy({ protectedRoutes: ["/dashboard"] });
56
+ * export const proxy = createAziridProxy({
57
+ * protectedRoutes: ["/dashboard"],
58
+ * loginUrl: "/login",
59
+ * });
55
60
  * export const config = { matcher: ["/((?!_next|favicon.ico|api/).*)"] };
56
61
  * ```
57
62
  */
58
- declare function createAziridProxy(options?: AziridProxyOptions): (request: NextRequest) => NextResponse;
59
- /** Default proxy export for Next.js 16+ (no route protection, only forwards token) */
60
- declare const aziridProxy: (request: NextRequest) => NextResponse;
63
+ declare function createAziridProxy(options?: AziridProxyOptions): (request: NextRequest) => Promise<NextResponse>;
64
+ /** Default proxy export for Next.js 16+ (no route protection, only validates + forwards token) */
65
+ declare const aziridProxy: (request: NextRequest) => Promise<NextResponse>;
61
66
 
62
67
  export { type AziridProxyOptions, aziridProxy, createAziridProxy };
@@ -1,23 +1,39 @@
1
1
  import { NextResponse } from 'next/server';
2
+ import { jwtVerify, createRemoteJWKSet } from 'jose';
2
3
 
3
4
  // src/next-proxy.ts
5
+ var jwks = null;
6
+ function getJwks(jwksUrl) {
7
+ if (jwks) return jwks;
8
+ const url = jwksUrl ?? `${process.env.AZIRID_API_URL ?? "https://api.azirid.com"}/v1/.well-known/jwks.json`;
9
+ jwks = createRemoteJWKSet(new URL(url));
10
+ return jwks;
11
+ }
4
12
  function createRequestInterceptor(options) {
5
13
  const cookieName = options?.cookieName ?? "__session";
6
14
  const loginUrl = options?.loginUrl ?? "/login";
7
15
  const defaultPublic = ["/login", "/signup", "/auth/handoff"];
8
16
  const publicRoutes = options?.publicRoutes ? [.../* @__PURE__ */ new Set([...options.publicRoutes, "/auth/handoff"])] : defaultPublic;
9
17
  const protectedRoutes = options?.protectedRoutes;
10
- return function handler(request) {
18
+ return async function handler(request) {
11
19
  const { pathname } = request.nextUrl;
12
20
  const token = request.cookies.get(cookieName)?.value;
13
21
  const response = NextResponse.next();
14
22
  if (token) {
15
- response.headers.set("x-azirid-token", token);
23
+ try {
24
+ const keySet = getJwks(options?.jwksUrl);
25
+ const { payload } = await jwtVerify(token, keySet);
26
+ response.headers.set("x-azirid-token", token);
27
+ if (payload.sub) response.headers.set("x-azirid-user-id", payload.sub);
28
+ } catch {
29
+ response.headers.set("Set-Cookie", `${cookieName}=; Path=/; Max-Age=0; SameSite=Lax`);
30
+ }
16
31
  }
17
32
  if (protectedRoutes) {
33
+ const hasValidToken = response.headers.has("x-azirid-token");
18
34
  const isPublic = publicRoutes.some((r) => pathname.startsWith(r));
19
35
  const isProtected = protectedRoutes.some((r) => pathname.startsWith(r));
20
- if (isProtected && !isPublic && !token) {
36
+ if (isProtected && !isPublic && !hasValidToken) {
21
37
  const url = request.nextUrl.clone();
22
38
  url.pathname = loginUrl;
23
39
  url.searchParams.set("redirect", pathname);
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/next-proxy.ts"],"names":[],"mappings":";;;AA0CA,SAAS,yBAAyB,OAAA,EAA8B;AAC9D,EAAA,MAAM,UAAA,GAAa,SAAS,UAAA,IAAc,WAAA;AAC1C,EAAA,MAAM,QAAA,GAAW,SAAS,QAAA,IAAY,QAAA;AACtC,EAAA,MAAM,aAAA,GAAgB,CAAC,QAAA,EAAU,SAAA,EAAW,eAAe,CAAA;AAC3D,EAAA,MAAM,YAAA,GAAe,OAAA,EAAS,YAAA,GAC1B,CAAC,mBAAG,IAAI,GAAA,CAAI,CAAC,GAAG,OAAA,CAAQ,YAAA,EAAc,eAAe,CAAC,CAAC,CAAA,GACvD,aAAA;AACJ,EAAA,MAAM,kBAAkB,OAAA,EAAS,eAAA;AAEjC,EAAA,OAAO,SAAS,QAAQ,OAAA,EAAsB;AAC5C,IAAA,MAAM,EAAE,QAAA,EAAS,GAAI,OAAA,CAAQ,OAAA;AAC7B,IAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,OAAA,CAAQ,GAAA,CAAI,UAAU,CAAA,EAAG,KAAA;AAE/C,IAAA,MAAM,QAAA,GAAW,aAAa,IAAA,EAAK;AAGnC,IAAA,IAAI,KAAA,EAAO;AACT,MAAA,QAAA,CAAS,OAAA,CAAQ,GAAA,CAAI,gBAAA,EAAkB,KAAK,CAAA;AAAA,IAC9C;AAGA,IAAA,IAAI,eAAA,EAAiB;AACnB,MAAA,MAAM,QAAA,GAAW,aAAa,IAAA,CAAK,CAAC,MAAM,QAAA,CAAS,UAAA,CAAW,CAAC,CAAC,CAAA;AAChE,MAAA,MAAM,WAAA,GAAc,gBAAgB,IAAA,CAAK,CAAC,MAAM,QAAA,CAAS,UAAA,CAAW,CAAC,CAAC,CAAA;AAEtE,MAAA,IAAI,WAAA,IAAe,CAAC,QAAA,IAAY,CAAC,KAAA,EAAO;AACtC,QAAA,MAAM,GAAA,GAAM,OAAA,CAAQ,OAAA,CAAQ,KAAA,EAAM;AAClC,QAAA,GAAA,CAAI,QAAA,GAAW,QAAA;AACf,QAAA,GAAA,CAAI,YAAA,CAAa,GAAA,CAAI,UAAA,EAAY,QAAQ,CAAA;AACzC,QAAA,OAAO,YAAA,CAAa,SAAS,GAAG,CAAA;AAAA,MAClC;AAAA,IACF;AAEA,IAAA,OAAO,QAAA;AAAA,EACT,CAAA;AACF;AAyBO,SAAS,kBAAkB,OAAA,EAA8B;AAC9D,EAAA,OAAO,yBAAyB,OAAO,CAAA;AACzC;AAGO,IAAM,cAAc,iBAAA","file":"next-proxy.js","sourcesContent":["/**\n * Next.js proxy and middleware utilities for Azirid Access.\n *\n * This entry point requires `next/server` and provides request interception\n * for route protection and token forwarding.\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({ protectedRoutes: [\"/dashboard\"] });\n * export const config = { matcher: [\"/((?!_next|favicon.ico|api/).*)\"] };\n * ```\n *\n * @packageDocumentation\n */\n\nimport { NextResponse, type NextRequest } from 'next/server'\n\n// ─── Proxy / Middleware Options ──────────────────────────────\n\nexport interface AziridProxyOptions {\n /** Cookie name (default: \"__session\") */\n cookieName?: string\n /** Routes that require authentication (glob patterns 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}\n\n\n// ─── Shared proxy/middleware logic ───────────────────────────\n\nfunction createRequestInterceptor(options?: AziridProxyOptions) {\n const cookieName = options?.cookieName ?? '__session'\n const loginUrl = options?.loginUrl ?? '/login'\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 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 // Expose token as internal header for server components\n if (token) {\n response.headers.set('x-azirid-token', token)\n }\n\n // Route protection (only when protectedRoutes is configured)\n if (protectedRoutes) {\n const isPublic = publicRoutes.some((r) => pathname.startsWith(r))\n const isProtected = protectedRoutes.some((r) => pathname.startsWith(r))\n\n if (isProtected && !isPublic && !token) {\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 proxy for Next.js 16+.\n *\n * In Next.js 16, `middleware.ts` is renamed to `proxy.ts` and the\n * exported function must be named `proxy`.\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({ protectedRoutes: [\"/dashboard\"] });\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 forwards token) */\nexport const aziridProxy = createAziridProxy()\n\n"]}
1
+ {"version":3,"sources":["../src/next-proxy.ts"],"names":[],"mappings":";;;;AA+CA,IAAI,IAAA,GAAqD,IAAA;AAEzD,SAAS,QAAQ,OAAA,EAAyD;AACxE,EAAA,IAAI,MAAM,OAAO,IAAA;AACjB,EAAA,MAAM,MACJ,OAAA,IACA,CAAA,EAAG,OAAA,CAAQ,GAAA,CAAI,kBAAkB,wBAAwB,CAAA,yBAAA,CAAA;AAC3D,EAAA,IAAA,GAAO,kBAAA,CAAmB,IAAI,GAAA,CAAI,GAAG,CAAC,CAAA;AACtC,EAAA,OAAO,IAAA;AACT;AAIA,SAAS,yBAAyB,OAAA,EAA8B;AAC9D,EAAA,MAAM,UAAA,GAAa,SAAS,UAAA,IAAc,WAAA;AAC1C,EAAA,MAAM,QAAA,GAAW,SAAS,QAAA,IAAY,QAAA;AACtC,EAAA,MAAM,aAAA,GAAgB,CAAC,QAAA,EAAU,SAAA,EAAW,eAAe,CAAA;AAC3D,EAAA,MAAM,YAAA,GAAe,OAAA,EAAS,YAAA,GAC1B,CAAC,mBAAG,IAAI,GAAA,CAAI,CAAC,GAAG,OAAA,CAAQ,YAAA,EAAc,eAAe,CAAC,CAAC,CAAA,GACvD,aAAA;AACJ,EAAA,MAAM,kBAAkB,OAAA,EAAS,eAAA;AAEjC,EAAA,OAAO,eAAe,QAAQ,OAAA,EAAsB;AAClD,IAAA,MAAM,EAAE,QAAA,EAAS,GAAI,OAAA,CAAQ,OAAA;AAC7B,IAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,OAAA,CAAQ,GAAA,CAAI,UAAU,CAAA,EAAG,KAAA;AAE/C,IAAA,MAAM,QAAA,GAAW,aAAa,IAAA,EAAK;AAEnC,IAAA,IAAI,KAAA,EAAO;AACT,MAAA,IAAI;AACF,QAAA,MAAM,MAAA,GAAS,OAAA,CAAQ,OAAA,EAAS,OAAO,CAAA;AACvC,QAAA,MAAM,EAAE,OAAA,EAAQ,GAAI,MAAM,SAAA,CAAU,OAAO,MAAM,CAAA;AAEjD,QAAA,QAAA,CAAS,OAAA,CAAQ,GAAA,CAAI,gBAAA,EAAkB,KAAK,CAAA;AAC5C,QAAA,IAAI,QAAQ,GAAA,EAAK,QAAA,CAAS,QAAQ,GAAA,CAAI,kBAAA,EAAoB,QAAQ,GAAG,CAAA;AAAA,MACvE,CAAA,CAAA,MAAQ;AAEN,QAAA,QAAA,CAAS,OAAA,CAAQ,GAAA,CAAI,YAAA,EAAc,CAAA,EAAG,UAAU,CAAA,kCAAA,CAAoC,CAAA;AAAA,MACtF;AAAA,IACF;AAGA,IAAA,IAAI,eAAA,EAAiB;AACnB,MAAA,MAAM,aAAA,GAAgB,QAAA,CAAS,OAAA,CAAQ,GAAA,CAAI,gBAAgB,CAAA;AAC3D,MAAA,MAAM,QAAA,GAAW,aAAa,IAAA,CAAK,CAAC,MAAM,QAAA,CAAS,UAAA,CAAW,CAAC,CAAC,CAAA;AAChE,MAAA,MAAM,WAAA,GAAc,gBAAgB,IAAA,CAAK,CAAC,MAAM,QAAA,CAAS,UAAA,CAAW,CAAC,CAAC,CAAA;AAEtE,MAAA,IAAI,WAAA,IAAe,CAAC,QAAA,IAAY,CAAC,aAAA,EAAe;AAC9C,QAAA,MAAM,GAAA,GAAM,OAAA,CAAQ,OAAA,CAAQ,KAAA,EAAM;AAClC,QAAA,GAAA,CAAI,QAAA,GAAW,QAAA;AACf,QAAA,GAAA,CAAI,YAAA,CAAa,GAAA,CAAI,UAAA,EAAY,QAAQ,CAAA;AACzC,QAAA,OAAO,YAAA,CAAa,SAAS,GAAG,CAAA;AAAA,MAClC;AAAA,IACF;AAEA,IAAA,OAAO,QAAA;AAAA,EACT,CAAA;AACF;AAyBO,SAAS,kBAAkB,OAAA,EAA8B;AAC9D,EAAA,OAAO,yBAAyB,OAAO,CAAA;AACzC;AAGO,IAAM,cAAc,iBAAA","file":"next-proxy.js","sourcesContent":["/**\n * Next.js middleware for Azirid Access.\n *\n * Validates the `__session` JWT cookie using JWKS and provides\n * route protection and token 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 { createRemoteJWKSet, jwtVerify } 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 /** JWKS endpoint URL. Default: `${AZIRID_API_URL}/v1/.well-known/jwks.json` */\n jwksUrl?: string\n}\n\n// ─── JWKS (lazy-initialized, cached by jose internally) ─────\n\nlet jwks: ReturnType<typeof createRemoteJWKSet> | null = null\n\nfunction getJwks(jwksUrl?: string): ReturnType<typeof createRemoteJWKSet> {\n if (jwks) return jwks\n const url =\n jwksUrl ??\n `${process.env.AZIRID_API_URL ?? 'https://api.azirid.com'}/v1/.well-known/jwks.json`\n jwks = createRemoteJWKSet(new URL(url))\n return jwks\n}\n\n// ─── Middleware logic ───────────────────────────────────────\n\nfunction createRequestInterceptor(options?: AziridProxyOptions) {\n const cookieName = options?.cookieName ?? '__session'\n const loginUrl = options?.loginUrl ?? '/login'\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 keySet = getJwks(options?.jwksUrl)\n const { payload } = await jwtVerify(token, keySet)\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 {\n // Invalid or expired JWT — clear corrupted cookie\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/server.cjs CHANGED
@@ -17,42 +17,7 @@ function createServerAccess(options) {
17
17
  getAccessToken: getSessionToken
18
18
  };
19
19
  }
20
- function createSessionSyncHandler(options) {
21
- const name = options?.cookieName ?? "__session";
22
- const secure = options?.secure ?? false;
23
- const maxAge = options?.maxAge ?? 3600;
24
- return {
25
- async POST(req) {
26
- const { token } = await req.json();
27
- if (!token || typeof token !== "string") {
28
- return new Response(JSON.stringify({ error: "Missing token" }), {
29
- status: 400,
30
- headers: { "Content-Type": "application/json" }
31
- });
32
- }
33
- const parts = [`${name}=${token}`, "Path=/", "HttpOnly", "SameSite=Lax", `Max-Age=${maxAge}`];
34
- if (secure) parts.push("Secure");
35
- return new Response(JSON.stringify({ ok: true }), {
36
- headers: {
37
- "Content-Type": "application/json",
38
- "Set-Cookie": parts.join("; ")
39
- }
40
- });
41
- },
42
- async DELETE() {
43
- const parts = [`${name}=`, "Path=/", "HttpOnly", "SameSite=Lax", "Max-Age=0"];
44
- if (secure) parts.push("Secure");
45
- return new Response(JSON.stringify({ ok: true }), {
46
- headers: {
47
- "Content-Type": "application/json",
48
- "Set-Cookie": parts.join("; ")
49
- }
50
- });
51
- }
52
- };
53
- }
54
20
 
55
21
  exports.createServerAccess = createServerAccess;
56
- exports.createSessionSyncHandler = createSessionSyncHandler;
57
22
  //# sourceMappingURL=server.cjs.map
58
23
  //# sourceMappingURL=server.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/server.ts"],"names":[],"mappings":";;;AAgFO,SAAS,mBAAmB,OAAA,EAA4C;AAC7E,EAAA,MAAM,EAAE,OAAA,EAAS,UAAA,GAAa,WAAA,EAAY,GAAI,OAAA;AAE9C,EAAA,eAAe,eAAA,GAA0C;AACvD,IAAA,IAAI;AACF,MAAA,MAAM,SAAS,OAAA,EAAQ;AAEvB,MAAA,MAAM,WAAA,GAAc,MAAA,YAAkB,OAAA,GAAU,MAAM,MAAA,GAAS,MAAA;AAC/D,MAAA,OAAO,WAAA,CAAY,GAAA,CAAI,UAAU,CAAA,EAAG,KAAA,IAAS,IAAA;AAAA,IAC/C,CAAA,CAAA,MAAQ;AACN,MAAA,OAAO,IAAA;AAAA,IACT;AAAA,EACF;AAEA,EAAA,OAAO;AAAA,IACL,eAAA;AAAA,IACA,cAAA,EAAgB;AAAA,GAClB;AACF;AAyBO,SAAS,yBAAyB,OAAA,EAA8B;AACrE,EAAA,MAAM,IAAA,GAAO,SAAS,UAAA,IAAc,WAAA;AACpC,EAAA,MAAM,MAAA,GAAS,SAAS,MAAA,IAAU,KAAA;AAClC,EAAA,MAAM,MAAA,GAAS,SAAS,MAAA,IAAU,IAAA;AAElC,EAAA,OAAO;AAAA,IACL,MAAM,KAAK,GAAA,EAAc;AACvB,MAAA,MAAM,EAAE,KAAA,EAAM,GAAI,MAAM,IAAI,IAAA,EAAK;AACjC,MAAA,IAAI,CAAC,KAAA,IAAS,OAAO,KAAA,KAAU,QAAA,EAAU;AACvC,QAAA,OAAO,IAAI,SAAS,IAAA,CAAK,SAAA,CAAU,EAAE,KAAA,EAAO,eAAA,EAAiB,CAAA,EAAG;AAAA,UAC9D,MAAA,EAAQ,GAAA;AAAA,UACR,OAAA,EAAS,EAAE,cAAA,EAAgB,kBAAA;AAAmB,SAC/C,CAAA;AAAA,MACH;AACA,MAAA,MAAM,KAAA,GAAQ,CAAC,CAAA,EAAG,IAAI,CAAA,CAAA,EAAI,KAAK,CAAA,CAAA,EAAI,QAAA,EAAU,UAAA,EAAY,cAAA,EAAgB,CAAA,QAAA,EAAW,MAAM,CAAA,CAAE,CAAA;AAC5F,MAAA,IAAI,MAAA,EAAQ,KAAA,CAAM,IAAA,CAAK,QAAQ,CAAA;AAC/B,MAAA,OAAO,IAAI,SAAS,IAAA,CAAK,SAAA,CAAU,EAAE,EAAA,EAAI,IAAA,EAAM,CAAA,EAAG;AAAA,QAChD,OAAA,EAAS;AAAA,UACP,cAAA,EAAgB,kBAAA;AAAA,UAChB,YAAA,EAAc,KAAA,CAAM,IAAA,CAAK,IAAI;AAAA;AAC/B,OACD,CAAA;AAAA,IACH,CAAA;AAAA,IACA,MAAM,MAAA,GAAS;AACb,MAAA,MAAM,KAAA,GAAQ,CAAC,CAAA,EAAG,IAAI,KAAK,QAAA,EAAU,UAAA,EAAY,gBAAgB,WAAW,CAAA;AAC5E,MAAA,IAAI,MAAA,EAAQ,KAAA,CAAM,IAAA,CAAK,QAAQ,CAAA;AAC/B,MAAA,OAAO,IAAI,SAAS,IAAA,CAAK,SAAA,CAAU,EAAE,EAAA,EAAI,IAAA,EAAM,CAAA,EAAG;AAAA,QAChD,OAAA,EAAS;AAAA,UACP,cAAA,EAAgB,kBAAA;AAAA,UAChB,YAAA,EAAc,KAAA,CAAM,IAAA,CAAK,IAAI;AAAA;AAC/B,OACD,CAAA;AAAA,IACH;AAAA,GACF;AACF","file":"server.cjs","sourcesContent":["/**\n * Server-side utilities for Next.js (App Router).\n *\n * Use this entry point in Server Components, Server Actions, and Route Handlers\n * to read the authenticated user's session token from the httpOnly `__session` cookie.\n *\n * @example\n * ```ts\n * // lib/access-server.ts\n * import { cookies } from \"next/headers\";\n * import { createServerAccess } from \"azirid-react/server\";\n * export const { getSessionToken } = createServerAccess({ cookies });\n * ```\n *\n * ```ts\n * // app/actions/profile.ts\n * \"use server\";\n * import { getSessionToken } from \"@/lib/access-server\";\n *\n * export async function getProfile() {\n * const token = await getSessionToken();\n * if (!token) throw new Error(\"Not authenticated\");\n *\n * const res = await fetch(\"https://api.myapp.com/v1/users/auth/me\", {\n * headers: { Authorization: `Bearer ${token}` },\n * });\n * return res.json();\n * }\n * ```\n *\n * @packageDocumentation\n */\n\n/** Minimal cookie store interface (subset of Next.js ReadonlyRequestCookies) */\ninterface CookieStore {\n get(name: string): { value: string } | undefined\n}\n\n/** The `cookies` function from `next/headers` */\ntype CookiesFn = () => CookieStore | Promise<CookieStore>\n\nexport interface ServerAccessOptions {\n /**\n * The `cookies` function imported from `next/headers`.\n * Required — pass it explicitly to avoid bundler issues with dynamic imports.\n *\n * @example\n * ```ts\n * import { cookies } from \"next/headers\";\n * createServerAccess({ cookies });\n * ```\n */\n cookies: CookiesFn\n\n /**\n * Name of the httpOnly cookie that carries the access token.\n * Must match the cookie set by the Azirid API.\n * @default \"__session\"\n */\n cookieName?: string\n}\n\nexport interface ServerAccess {\n /**\n * Read the raw JWT access token from the session cookie.\n * Returns `null` when no cookie is present or when called\n * outside a Next.js server context.\n */\n getSessionToken: () => Promise<string | null>\n\n /** Alias for {@link getSessionToken}. */\n getAccessToken: () => Promise<string | null>\n}\n\n/**\n * Create server-side helpers bound to the session cookie.\n *\n * Call once at module scope, then use the returned functions\n * in any Server Component, Server Action, or Route Handler.\n */\nexport function createServerAccess(options: ServerAccessOptions): ServerAccess {\n const { cookies, cookieName = '__session' } = options\n\n async function getSessionToken(): Promise<string | null> {\n try {\n const result = cookies()\n // Next.js 15+: cookies() returns a Promise\n const cookieStore = result instanceof Promise ? await result : result\n return cookieStore.get(cookieName)?.value ?? null\n } catch {\n return null\n }\n }\n\n return {\n getSessionToken,\n getAccessToken: getSessionToken,\n }\n}\n\n// ─── Session Sync Handler (cross-origin dev support) ─────────\n\nexport interface SessionSyncOptions {\n /** Cookie name (default: \"__session\") */\n cookieName?: string\n /** Set Secure flag on cookie (default: false) */\n secure?: boolean\n /** Cookie max age in seconds (default: 3600 = 1h) */\n maxAge?: number\n}\n\n/**\n * Create a route handler that syncs the access token to a local httpOnly cookie.\n *\n * Use this in a Next.js App Router route to bridge cross-origin sessions:\n *\n * @example\n * ```ts\n * // app/api/auth/session/route.ts\n * import { createSessionSyncHandler } from \"azirid-react/server\";\n * export const { POST, DELETE } = createSessionSyncHandler();\n * ```\n */\nexport function createSessionSyncHandler(options?: SessionSyncOptions) {\n const name = options?.cookieName ?? '__session'\n const secure = options?.secure ?? false\n const maxAge = options?.maxAge ?? 3600\n\n return {\n async POST(req: Request) {\n const { token } = await req.json()\n if (!token || typeof token !== 'string') {\n return new Response(JSON.stringify({ error: 'Missing token' }), {\n status: 400,\n headers: { 'Content-Type': 'application/json' },\n })\n }\n const parts = [`${name}=${token}`, 'Path=/', 'HttpOnly', 'SameSite=Lax', `Max-Age=${maxAge}`]\n if (secure) parts.push('Secure')\n return new Response(JSON.stringify({ ok: true }), {\n headers: {\n 'Content-Type': 'application/json',\n 'Set-Cookie': parts.join('; '),\n },\n })\n },\n async DELETE() {\n const parts = [`${name}=`, 'Path=/', 'HttpOnly', 'SameSite=Lax', 'Max-Age=0']\n if (secure) parts.push('Secure')\n return new Response(JSON.stringify({ ok: true }), {\n headers: {\n 'Content-Type': 'application/json',\n 'Set-Cookie': parts.join('; '),\n },\n })\n },\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/server.ts"],"names":[],"mappings":";;;AAgFO,SAAS,mBAAmB,OAAA,EAA4C;AAC7E,EAAA,MAAM,EAAE,OAAA,EAAS,UAAA,GAAa,WAAA,EAAY,GAAI,OAAA;AAE9C,EAAA,eAAe,eAAA,GAA0C;AACvD,IAAA,IAAI;AACF,MAAA,MAAM,SAAS,OAAA,EAAQ;AAEvB,MAAA,MAAM,WAAA,GAAc,MAAA,YAAkB,OAAA,GAAU,MAAM,MAAA,GAAS,MAAA;AAC/D,MAAA,OAAO,WAAA,CAAY,GAAA,CAAI,UAAU,CAAA,EAAG,KAAA,IAAS,IAAA;AAAA,IAC/C,CAAA,CAAA,MAAQ;AACN,MAAA,OAAO,IAAA;AAAA,IACT;AAAA,EACF;AAEA,EAAA,OAAO;AAAA,IACL,eAAA;AAAA,IACA,cAAA,EAAgB;AAAA,GAClB;AACF","file":"server.cjs","sourcesContent":["/**\n * Server-side utilities for Next.js (App Router).\n *\n * Use this entry point in Server Components, Server Actions, and Route Handlers\n * to read the authenticated user's session token from the httpOnly `__session` cookie.\n *\n * @example\n * ```ts\n * // lib/access-server.ts\n * import { cookies } from \"next/headers\";\n * import { createServerAccess } from \"azirid-react/server\";\n * export const { getSessionToken } = createServerAccess({ cookies });\n * ```\n *\n * ```ts\n * // app/actions/profile.ts\n * \"use server\";\n * import { getSessionToken } from \"@/lib/access-server\";\n *\n * export async function getProfile() {\n * const token = await getSessionToken();\n * if (!token) throw new Error(\"Not authenticated\");\n *\n * const res = await fetch(\"https://api.myapp.com/v1/users/auth/me\", {\n * headers: { Authorization: `Bearer ${token}` },\n * });\n * return res.json();\n * }\n * ```\n *\n * @packageDocumentation\n */\n\n/** Minimal cookie store interface (subset of Next.js ReadonlyRequestCookies) */\ninterface CookieStore {\n get(name: string): { value: string } | undefined\n}\n\n/** The `cookies` function from `next/headers` */\ntype CookiesFn = () => CookieStore | Promise<CookieStore>\n\nexport interface ServerAccessOptions {\n /**\n * The `cookies` function imported from `next/headers`.\n * Required — pass it explicitly to avoid bundler issues with dynamic imports.\n *\n * @example\n * ```ts\n * import { cookies } from \"next/headers\";\n * createServerAccess({ cookies });\n * ```\n */\n cookies: CookiesFn\n\n /**\n * Name of the httpOnly cookie that carries the access token.\n * Must match the cookie set by the Azirid API.\n * @default \"__session\"\n */\n cookieName?: string\n}\n\nexport interface ServerAccess {\n /**\n * Read the raw JWT access token from the session cookie.\n * Returns `null` when no cookie is present or when called\n * outside a Next.js server context.\n */\n getSessionToken: () => Promise<string | null>\n\n /** Alias for {@link getSessionToken}. */\n getAccessToken: () => Promise<string | null>\n}\n\n/**\n * Create server-side helpers bound to the session cookie.\n *\n * Call once at module scope, then use the returned functions\n * in any Server Component, Server Action, or Route Handler.\n */\nexport function createServerAccess(options: ServerAccessOptions): ServerAccess {\n const { cookies, cookieName = '__session' } = options\n\n async function getSessionToken(): Promise<string | null> {\n try {\n const result = cookies()\n // Next.js 15+: cookies() returns a Promise\n const cookieStore = result instanceof Promise ? await result : result\n return cookieStore.get(cookieName)?.value ?? null\n } catch {\n return null\n }\n }\n\n return {\n getSessionToken,\n getAccessToken: getSessionToken,\n }\n}\n\n"]}
package/dist/server.d.cts CHANGED
@@ -74,29 +74,5 @@ interface ServerAccess {
74
74
  * in any Server Component, Server Action, or Route Handler.
75
75
  */
76
76
  declare function createServerAccess(options: ServerAccessOptions): ServerAccess;
77
- interface SessionSyncOptions {
78
- /** Cookie name (default: "__session") */
79
- cookieName?: string;
80
- /** Set Secure flag on cookie (default: false) */
81
- secure?: boolean;
82
- /** Cookie max age in seconds (default: 3600 = 1h) */
83
- maxAge?: number;
84
- }
85
- /**
86
- * Create a route handler that syncs the access token to a local httpOnly cookie.
87
- *
88
- * Use this in a Next.js App Router route to bridge cross-origin sessions:
89
- *
90
- * @example
91
- * ```ts
92
- * // app/api/auth/session/route.ts
93
- * import { createSessionSyncHandler } from "azirid-react/server";
94
- * export const { POST, DELETE } = createSessionSyncHandler();
95
- * ```
96
- */
97
- declare function createSessionSyncHandler(options?: SessionSyncOptions): {
98
- POST(req: Request): Promise<Response>;
99
- DELETE(): Promise<Response>;
100
- };
101
77
 
102
- export { type ServerAccess, type ServerAccessOptions, type SessionSyncOptions, createServerAccess, createSessionSyncHandler };
78
+ export { type ServerAccess, type ServerAccessOptions, createServerAccess };
package/dist/server.d.ts CHANGED
@@ -74,29 +74,5 @@ interface ServerAccess {
74
74
  * in any Server Component, Server Action, or Route Handler.
75
75
  */
76
76
  declare function createServerAccess(options: ServerAccessOptions): ServerAccess;
77
- interface SessionSyncOptions {
78
- /** Cookie name (default: "__session") */
79
- cookieName?: string;
80
- /** Set Secure flag on cookie (default: false) */
81
- secure?: boolean;
82
- /** Cookie max age in seconds (default: 3600 = 1h) */
83
- maxAge?: number;
84
- }
85
- /**
86
- * Create a route handler that syncs the access token to a local httpOnly cookie.
87
- *
88
- * Use this in a Next.js App Router route to bridge cross-origin sessions:
89
- *
90
- * @example
91
- * ```ts
92
- * // app/api/auth/session/route.ts
93
- * import { createSessionSyncHandler } from "azirid-react/server";
94
- * export const { POST, DELETE } = createSessionSyncHandler();
95
- * ```
96
- */
97
- declare function createSessionSyncHandler(options?: SessionSyncOptions): {
98
- POST(req: Request): Promise<Response>;
99
- DELETE(): Promise<Response>;
100
- };
101
77
 
102
- export { type ServerAccess, type ServerAccessOptions, type SessionSyncOptions, createServerAccess, createSessionSyncHandler };
78
+ export { type ServerAccess, type ServerAccessOptions, createServerAccess };
package/dist/server.js CHANGED
@@ -15,41 +15,7 @@ function createServerAccess(options) {
15
15
  getAccessToken: getSessionToken
16
16
  };
17
17
  }
18
- function createSessionSyncHandler(options) {
19
- const name = options?.cookieName ?? "__session";
20
- const secure = options?.secure ?? false;
21
- const maxAge = options?.maxAge ?? 3600;
22
- return {
23
- async POST(req) {
24
- const { token } = await req.json();
25
- if (!token || typeof token !== "string") {
26
- return new Response(JSON.stringify({ error: "Missing token" }), {
27
- status: 400,
28
- headers: { "Content-Type": "application/json" }
29
- });
30
- }
31
- const parts = [`${name}=${token}`, "Path=/", "HttpOnly", "SameSite=Lax", `Max-Age=${maxAge}`];
32
- if (secure) parts.push("Secure");
33
- return new Response(JSON.stringify({ ok: true }), {
34
- headers: {
35
- "Content-Type": "application/json",
36
- "Set-Cookie": parts.join("; ")
37
- }
38
- });
39
- },
40
- async DELETE() {
41
- const parts = [`${name}=`, "Path=/", "HttpOnly", "SameSite=Lax", "Max-Age=0"];
42
- if (secure) parts.push("Secure");
43
- return new Response(JSON.stringify({ ok: true }), {
44
- headers: {
45
- "Content-Type": "application/json",
46
- "Set-Cookie": parts.join("; ")
47
- }
48
- });
49
- }
50
- };
51
- }
52
18
 
53
- export { createServerAccess, createSessionSyncHandler };
19
+ export { createServerAccess };
54
20
  //# sourceMappingURL=server.js.map
55
21
  //# sourceMappingURL=server.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/server.ts"],"names":[],"mappings":";AAgFO,SAAS,mBAAmB,OAAA,EAA4C;AAC7E,EAAA,MAAM,EAAE,OAAA,EAAS,UAAA,GAAa,WAAA,EAAY,GAAI,OAAA;AAE9C,EAAA,eAAe,eAAA,GAA0C;AACvD,IAAA,IAAI;AACF,MAAA,MAAM,SAAS,OAAA,EAAQ;AAEvB,MAAA,MAAM,WAAA,GAAc,MAAA,YAAkB,OAAA,GAAU,MAAM,MAAA,GAAS,MAAA;AAC/D,MAAA,OAAO,WAAA,CAAY,GAAA,CAAI,UAAU,CAAA,EAAG,KAAA,IAAS,IAAA;AAAA,IAC/C,CAAA,CAAA,MAAQ;AACN,MAAA,OAAO,IAAA;AAAA,IACT;AAAA,EACF;AAEA,EAAA,OAAO;AAAA,IACL,eAAA;AAAA,IACA,cAAA,EAAgB;AAAA,GAClB;AACF;AAyBO,SAAS,yBAAyB,OAAA,EAA8B;AACrE,EAAA,MAAM,IAAA,GAAO,SAAS,UAAA,IAAc,WAAA;AACpC,EAAA,MAAM,MAAA,GAAS,SAAS,MAAA,IAAU,KAAA;AAClC,EAAA,MAAM,MAAA,GAAS,SAAS,MAAA,IAAU,IAAA;AAElC,EAAA,OAAO;AAAA,IACL,MAAM,KAAK,GAAA,EAAc;AACvB,MAAA,MAAM,EAAE,KAAA,EAAM,GAAI,MAAM,IAAI,IAAA,EAAK;AACjC,MAAA,IAAI,CAAC,KAAA,IAAS,OAAO,KAAA,KAAU,QAAA,EAAU;AACvC,QAAA,OAAO,IAAI,SAAS,IAAA,CAAK,SAAA,CAAU,EAAE,KAAA,EAAO,eAAA,EAAiB,CAAA,EAAG;AAAA,UAC9D,MAAA,EAAQ,GAAA;AAAA,UACR,OAAA,EAAS,EAAE,cAAA,EAAgB,kBAAA;AAAmB,SAC/C,CAAA;AAAA,MACH;AACA,MAAA,MAAM,KAAA,GAAQ,CAAC,CAAA,EAAG,IAAI,CAAA,CAAA,EAAI,KAAK,CAAA,CAAA,EAAI,QAAA,EAAU,UAAA,EAAY,cAAA,EAAgB,CAAA,QAAA,EAAW,MAAM,CAAA,CAAE,CAAA;AAC5F,MAAA,IAAI,MAAA,EAAQ,KAAA,CAAM,IAAA,CAAK,QAAQ,CAAA;AAC/B,MAAA,OAAO,IAAI,SAAS,IAAA,CAAK,SAAA,CAAU,EAAE,EAAA,EAAI,IAAA,EAAM,CAAA,EAAG;AAAA,QAChD,OAAA,EAAS;AAAA,UACP,cAAA,EAAgB,kBAAA;AAAA,UAChB,YAAA,EAAc,KAAA,CAAM,IAAA,CAAK,IAAI;AAAA;AAC/B,OACD,CAAA;AAAA,IACH,CAAA;AAAA,IACA,MAAM,MAAA,GAAS;AACb,MAAA,MAAM,KAAA,GAAQ,CAAC,CAAA,EAAG,IAAI,KAAK,QAAA,EAAU,UAAA,EAAY,gBAAgB,WAAW,CAAA;AAC5E,MAAA,IAAI,MAAA,EAAQ,KAAA,CAAM,IAAA,CAAK,QAAQ,CAAA;AAC/B,MAAA,OAAO,IAAI,SAAS,IAAA,CAAK,SAAA,CAAU,EAAE,EAAA,EAAI,IAAA,EAAM,CAAA,EAAG;AAAA,QAChD,OAAA,EAAS;AAAA,UACP,cAAA,EAAgB,kBAAA;AAAA,UAChB,YAAA,EAAc,KAAA,CAAM,IAAA,CAAK,IAAI;AAAA;AAC/B,OACD,CAAA;AAAA,IACH;AAAA,GACF;AACF","file":"server.js","sourcesContent":["/**\n * Server-side utilities for Next.js (App Router).\n *\n * Use this entry point in Server Components, Server Actions, and Route Handlers\n * to read the authenticated user's session token from the httpOnly `__session` cookie.\n *\n * @example\n * ```ts\n * // lib/access-server.ts\n * import { cookies } from \"next/headers\";\n * import { createServerAccess } from \"azirid-react/server\";\n * export const { getSessionToken } = createServerAccess({ cookies });\n * ```\n *\n * ```ts\n * // app/actions/profile.ts\n * \"use server\";\n * import { getSessionToken } from \"@/lib/access-server\";\n *\n * export async function getProfile() {\n * const token = await getSessionToken();\n * if (!token) throw new Error(\"Not authenticated\");\n *\n * const res = await fetch(\"https://api.myapp.com/v1/users/auth/me\", {\n * headers: { Authorization: `Bearer ${token}` },\n * });\n * return res.json();\n * }\n * ```\n *\n * @packageDocumentation\n */\n\n/** Minimal cookie store interface (subset of Next.js ReadonlyRequestCookies) */\ninterface CookieStore {\n get(name: string): { value: string } | undefined\n}\n\n/** The `cookies` function from `next/headers` */\ntype CookiesFn = () => CookieStore | Promise<CookieStore>\n\nexport interface ServerAccessOptions {\n /**\n * The `cookies` function imported from `next/headers`.\n * Required — pass it explicitly to avoid bundler issues with dynamic imports.\n *\n * @example\n * ```ts\n * import { cookies } from \"next/headers\";\n * createServerAccess({ cookies });\n * ```\n */\n cookies: CookiesFn\n\n /**\n * Name of the httpOnly cookie that carries the access token.\n * Must match the cookie set by the Azirid API.\n * @default \"__session\"\n */\n cookieName?: string\n}\n\nexport interface ServerAccess {\n /**\n * Read the raw JWT access token from the session cookie.\n * Returns `null` when no cookie is present or when called\n * outside a Next.js server context.\n */\n getSessionToken: () => Promise<string | null>\n\n /** Alias for {@link getSessionToken}. */\n getAccessToken: () => Promise<string | null>\n}\n\n/**\n * Create server-side helpers bound to the session cookie.\n *\n * Call once at module scope, then use the returned functions\n * in any Server Component, Server Action, or Route Handler.\n */\nexport function createServerAccess(options: ServerAccessOptions): ServerAccess {\n const { cookies, cookieName = '__session' } = options\n\n async function getSessionToken(): Promise<string | null> {\n try {\n const result = cookies()\n // Next.js 15+: cookies() returns a Promise\n const cookieStore = result instanceof Promise ? await result : result\n return cookieStore.get(cookieName)?.value ?? null\n } catch {\n return null\n }\n }\n\n return {\n getSessionToken,\n getAccessToken: getSessionToken,\n }\n}\n\n// ─── Session Sync Handler (cross-origin dev support) ─────────\n\nexport interface SessionSyncOptions {\n /** Cookie name (default: \"__session\") */\n cookieName?: string\n /** Set Secure flag on cookie (default: false) */\n secure?: boolean\n /** Cookie max age in seconds (default: 3600 = 1h) */\n maxAge?: number\n}\n\n/**\n * Create a route handler that syncs the access token to a local httpOnly cookie.\n *\n * Use this in a Next.js App Router route to bridge cross-origin sessions:\n *\n * @example\n * ```ts\n * // app/api/auth/session/route.ts\n * import { createSessionSyncHandler } from \"azirid-react/server\";\n * export const { POST, DELETE } = createSessionSyncHandler();\n * ```\n */\nexport function createSessionSyncHandler(options?: SessionSyncOptions) {\n const name = options?.cookieName ?? '__session'\n const secure = options?.secure ?? false\n const maxAge = options?.maxAge ?? 3600\n\n return {\n async POST(req: Request) {\n const { token } = await req.json()\n if (!token || typeof token !== 'string') {\n return new Response(JSON.stringify({ error: 'Missing token' }), {\n status: 400,\n headers: { 'Content-Type': 'application/json' },\n })\n }\n const parts = [`${name}=${token}`, 'Path=/', 'HttpOnly', 'SameSite=Lax', `Max-Age=${maxAge}`]\n if (secure) parts.push('Secure')\n return new Response(JSON.stringify({ ok: true }), {\n headers: {\n 'Content-Type': 'application/json',\n 'Set-Cookie': parts.join('; '),\n },\n })\n },\n async DELETE() {\n const parts = [`${name}=`, 'Path=/', 'HttpOnly', 'SameSite=Lax', 'Max-Age=0']\n if (secure) parts.push('Secure')\n return new Response(JSON.stringify({ ok: true }), {\n headers: {\n 'Content-Type': 'application/json',\n 'Set-Cookie': parts.join('; '),\n },\n })\n },\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/server.ts"],"names":[],"mappings":";AAgFO,SAAS,mBAAmB,OAAA,EAA4C;AAC7E,EAAA,MAAM,EAAE,OAAA,EAAS,UAAA,GAAa,WAAA,EAAY,GAAI,OAAA;AAE9C,EAAA,eAAe,eAAA,GAA0C;AACvD,IAAA,IAAI;AACF,MAAA,MAAM,SAAS,OAAA,EAAQ;AAEvB,MAAA,MAAM,WAAA,GAAc,MAAA,YAAkB,OAAA,GAAU,MAAM,MAAA,GAAS,MAAA;AAC/D,MAAA,OAAO,WAAA,CAAY,GAAA,CAAI,UAAU,CAAA,EAAG,KAAA,IAAS,IAAA;AAAA,IAC/C,CAAA,CAAA,MAAQ;AACN,MAAA,OAAO,IAAA;AAAA,IACT;AAAA,EACF;AAEA,EAAA,OAAO;AAAA,IACL,eAAA;AAAA,IACA,cAAA,EAAgB;AAAA,GAClB;AACF","file":"server.js","sourcesContent":["/**\n * Server-side utilities for Next.js (App Router).\n *\n * Use this entry point in Server Components, Server Actions, and Route Handlers\n * to read the authenticated user's session token from the httpOnly `__session` cookie.\n *\n * @example\n * ```ts\n * // lib/access-server.ts\n * import { cookies } from \"next/headers\";\n * import { createServerAccess } from \"azirid-react/server\";\n * export const { getSessionToken } = createServerAccess({ cookies });\n * ```\n *\n * ```ts\n * // app/actions/profile.ts\n * \"use server\";\n * import { getSessionToken } from \"@/lib/access-server\";\n *\n * export async function getProfile() {\n * const token = await getSessionToken();\n * if (!token) throw new Error(\"Not authenticated\");\n *\n * const res = await fetch(\"https://api.myapp.com/v1/users/auth/me\", {\n * headers: { Authorization: `Bearer ${token}` },\n * });\n * return res.json();\n * }\n * ```\n *\n * @packageDocumentation\n */\n\n/** Minimal cookie store interface (subset of Next.js ReadonlyRequestCookies) */\ninterface CookieStore {\n get(name: string): { value: string } | undefined\n}\n\n/** The `cookies` function from `next/headers` */\ntype CookiesFn = () => CookieStore | Promise<CookieStore>\n\nexport interface ServerAccessOptions {\n /**\n * The `cookies` function imported from `next/headers`.\n * Required — pass it explicitly to avoid bundler issues with dynamic imports.\n *\n * @example\n * ```ts\n * import { cookies } from \"next/headers\";\n * createServerAccess({ cookies });\n * ```\n */\n cookies: CookiesFn\n\n /**\n * Name of the httpOnly cookie that carries the access token.\n * Must match the cookie set by the Azirid API.\n * @default \"__session\"\n */\n cookieName?: string\n}\n\nexport interface ServerAccess {\n /**\n * Read the raw JWT access token from the session cookie.\n * Returns `null` when no cookie is present or when called\n * outside a Next.js server context.\n */\n getSessionToken: () => Promise<string | null>\n\n /** Alias for {@link getSessionToken}. */\n getAccessToken: () => Promise<string | null>\n}\n\n/**\n * Create server-side helpers bound to the session cookie.\n *\n * Call once at module scope, then use the returned functions\n * in any Server Component, Server Action, or Route Handler.\n */\nexport function createServerAccess(options: ServerAccessOptions): ServerAccess {\n const { cookies, cookieName = '__session' } = options\n\n async function getSessionToken(): Promise<string | null> {\n try {\n const result = cookies()\n // Next.js 15+: cookies() returns a Promise\n const cookieStore = result instanceof Promise ? await result : result\n return cookieStore.get(cookieName)?.value ?? null\n } catch {\n return null\n }\n }\n\n return {\n getSessionToken,\n getAccessToken: getSessionToken,\n }\n}\n\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "azirid-react",
3
- "version": "0.13.2",
3
+ "version": "0.14.1",
4
4
  "description": "Authentication components for React and Next.js — Login, Register, powered by TanStack Query and Zod.",
5
5
  "author": "Azirid",
6
6
  "license": "MIT",
@@ -38,10 +38,12 @@
38
38
  "types": "./dist/index.d.ts",
39
39
  "typesVersions": {
40
40
  "*": {
41
- "next/handlers": ["./dist/next-handlers.d.ts"],
42
- "next/proxy": ["./dist/next-proxy.d.ts"],
43
- "next": ["./dist/next.d.ts"],
44
- "server": ["./dist/server.d.ts"]
41
+ "next/proxy": [
42
+ "./dist/next-proxy.d.ts"
43
+ ],
44
+ "server": [
45
+ "./dist/server.d.ts"
46
+ ]
45
47
  }
46
48
  },
47
49
  "exports": {
@@ -65,16 +67,6 @@
65
67
  "default": "./dist/server.cjs"
66
68
  }
67
69
  },
68
- "./next/handlers": {
69
- "import": {
70
- "types": "./dist/next-handlers.d.ts",
71
- "default": "./dist/next-handlers.js"
72
- },
73
- "require": {
74
- "types": "./dist/next-handlers.d.cts",
75
- "default": "./dist/next-handlers.cjs"
76
- }
77
- },
78
70
  "./next/proxy": {
79
71
  "import": {
80
72
  "types": "./dist/next-proxy.d.ts",
@@ -85,16 +77,6 @@
85
77
  "default": "./dist/next-proxy.cjs"
86
78
  }
87
79
  },
88
- "./next": {
89
- "import": {
90
- "types": "./dist/next.d.ts",
91
- "default": "./dist/next.js"
92
- },
93
- "require": {
94
- "types": "./dist/next.d.cts",
95
- "default": "./dist/next.cjs"
96
- }
97
- },
98
80
  "./styles.css": "./dist/styles.css"
99
81
  },
100
82
  "files": [
@@ -122,6 +104,7 @@
122
104
  "@hookform/resolvers": "^4.1.3",
123
105
  "class-variance-authority": "^0.7.1",
124
106
  "clsx": "^2.1.0",
107
+ "jose": "^5.10.0",
125
108
  "radix-ui": "^1.4.3",
126
109
  "react-hook-form": "^7.71.2",
127
110
  "tailwind-merge": "^2.3.0",