@djangocfg/nextjs 2.1.603 → 2.1.604
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 +1 -0
- package/dist/auth/index.d.mts +10 -0
- package/dist/auth/index.mjs +31 -0
- package/dist/auth/index.mjs.map +1 -0
- package/dist/i18n/routing.d.mts +2 -2
- package/package.json +16 -11
- package/src/auth/index.ts +48 -0
package/README.md
CHANGED
|
@@ -457,6 +457,7 @@ import { RedirectPage } from '@djangocfg/layouts/components/RedirectPage';
|
|
|
457
457
|
| `@djangocfg/nextjs/i18n/components` | `LocaleSwitcher` (`'use client'`) |
|
|
458
458
|
| `@djangocfg/nextjs/i18n/proxy` | `createProxy` for middleware |
|
|
459
459
|
| `@djangocfg/nextjs/i18n/navigation` | `Link`, `redirect`, `usePathname`, `useRouter` |
|
|
460
|
+
| `@djangocfg/nextjs/auth` | Server-side shared session cookie: `serverAuthHeaders`, `getServerAccessToken`, `hasServerSession` |
|
|
460
461
|
| `@djangocfg/nextjs/ai` | AI documentation search and MCP config |
|
|
461
462
|
| `@djangocfg/nextjs/config` | Base Next.js configuration factory |
|
|
462
463
|
| `@djangocfg/nextjs/pwa` | PWA client utilities (service worker registration) |
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** The access token of the signed-in user, or `null`. May be expired: the API decides. */
|
|
2
|
+
declare function getServerAccessToken(): Promise<string | null>;
|
|
3
|
+
/** The refresh token, or `null`. Rarely needed on the server. */
|
|
4
|
+
declare function getServerRefreshToken(): Promise<string | null>;
|
|
5
|
+
/** `{ Authorization: 'Bearer …' }` for a server-side fetch; `{}` when signed out. */
|
|
6
|
+
declare function serverAuthHeaders(): Promise<Record<string, string>>;
|
|
7
|
+
/** Whether a session cookie is present (not whether it is still valid). */
|
|
8
|
+
declare function hasServerSession(): Promise<boolean>;
|
|
9
|
+
|
|
10
|
+
export { getServerAccessToken, getServerRefreshToken, hasServerSession, serverAuthHeaders };
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// src/auth/index.ts
|
|
2
|
+
import { cookies } from "next/headers";
|
|
3
|
+
import { CFG_KEYS } from "@djangocfg/api/storage";
|
|
4
|
+
async function readSessionCookie(name) {
|
|
5
|
+
try {
|
|
6
|
+
const raw = (await cookies()).get(name)?.value;
|
|
7
|
+
return raw ? decodeURIComponent(raw) : null;
|
|
8
|
+
} catch {
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
function getServerAccessToken() {
|
|
13
|
+
return readSessionCookie(CFG_KEYS.accessToken.key);
|
|
14
|
+
}
|
|
15
|
+
function getServerRefreshToken() {
|
|
16
|
+
return readSessionCookie(CFG_KEYS.refreshToken.key);
|
|
17
|
+
}
|
|
18
|
+
async function serverAuthHeaders() {
|
|
19
|
+
const token = await getServerAccessToken();
|
|
20
|
+
return token ? { Authorization: `Bearer ${token}` } : {};
|
|
21
|
+
}
|
|
22
|
+
async function hasServerSession() {
|
|
23
|
+
return await getServerAccessToken() !== null || await getServerRefreshToken() !== null;
|
|
24
|
+
}
|
|
25
|
+
export {
|
|
26
|
+
getServerAccessToken,
|
|
27
|
+
getServerRefreshToken,
|
|
28
|
+
hasServerSession,
|
|
29
|
+
serverAuthHeaders
|
|
30
|
+
};
|
|
31
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/auth/index.ts"],"sourcesContent":["/**\n * Server-side view of the shared session cookie.\n *\n * `@djangocfg/api` keeps the JWT pair in cookies on the registrable domain, so a Server\n * Component, route handler or `generateMetadata` on any subdomain sees the same session\n * with no setup:\n *\n * ```ts\n * import { serverAuthHeaders } from '@djangocfg/nextjs/auth';\n * const res = await fetch(`${API}/cfg/accounts/profile/`, { headers: await serverAuthHeaders() });\n * ```\n *\n * The API authenticates the `Authorization` header only; this cookie is never an\n * authenticator by itself, so reading it here creates no CSRF surface.\n */\nimport { cookies } from 'next/headers';\nimport { CFG_KEYS } from '@djangocfg/api/storage';\n\nasync function readSessionCookie(name: string): Promise<string | null> {\n try {\n const raw = (await cookies()).get(name)?.value;\n return raw ? decodeURIComponent(raw) : null;\n } catch {\n // Outside a request scope (build time, static generation): no session.\n return null;\n }\n}\n\n/** The access token of the signed-in user, or `null`. May be expired: the API decides. */\nexport function getServerAccessToken(): Promise<string | null> {\n return readSessionCookie(CFG_KEYS.accessToken.key);\n}\n\n/** The refresh token, or `null`. Rarely needed on the server. */\nexport function getServerRefreshToken(): Promise<string | null> {\n return readSessionCookie(CFG_KEYS.refreshToken.key);\n}\n\n/** `{ Authorization: 'Bearer …' }` for a server-side fetch; `{}` when signed out. */\nexport async function serverAuthHeaders(): Promise<Record<string, string>> {\n const token = await getServerAccessToken();\n return token ? { Authorization: `Bearer ${token}` } : {};\n}\n\n/** Whether a session cookie is present (not whether it is still valid). */\nexport async function hasServerSession(): Promise<boolean> {\n return (await getServerAccessToken()) !== null || (await getServerRefreshToken()) !== null;\n}\n"],"mappings":";AAeA,SAAS,eAAe;AACxB,SAAS,gBAAgB;AAEzB,eAAe,kBAAkB,MAAsC;AACrE,MAAI;AACF,UAAM,OAAO,MAAM,QAAQ,GAAG,IAAI,IAAI,GAAG;AACzC,WAAO,MAAM,mBAAmB,GAAG,IAAI;AAAA,EACzC,QAAQ;AAEN,WAAO;AAAA,EACT;AACF;AAGO,SAAS,uBAA+C;AAC7D,SAAO,kBAAkB,SAAS,YAAY,GAAG;AACnD;AAGO,SAAS,wBAAgD;AAC9D,SAAO,kBAAkB,SAAS,aAAa,GAAG;AACpD;AAGA,eAAsB,oBAAqD;AACzE,QAAM,QAAQ,MAAM,qBAAqB;AACzC,SAAO,QAAQ,EAAE,eAAe,UAAU,KAAK,GAAG,IAAI,CAAC;AACzD;AAGA,eAAsB,mBAAqC;AACzD,SAAQ,MAAM,qBAAqB,MAAO,QAAS,MAAM,sBAAsB,MAAO;AACxF;","names":[]}
|
package/dist/i18n/routing.d.mts
CHANGED
|
@@ -24,6 +24,7 @@ declare function createRouting(config?: Partial<I18nConfig>): {
|
|
|
24
24
|
localePrefix?: next_intl_routing.LocalePrefix<string[], "always" | "as-needed" | "never"> | undefined;
|
|
25
25
|
domains?: undefined;
|
|
26
26
|
localeCookie?: boolean | {
|
|
27
|
+
name?: string | undefined;
|
|
27
28
|
maxAge?: number | undefined | undefined;
|
|
28
29
|
priority?: "low" | "medium" | "high" | undefined | undefined;
|
|
29
30
|
domain?: string | undefined | undefined;
|
|
@@ -31,7 +32,6 @@ declare function createRouting(config?: Partial<I18nConfig>): {
|
|
|
31
32
|
secure?: boolean | undefined | undefined;
|
|
32
33
|
sameSite?: true | false | "lax" | "strict" | "none" | undefined | undefined;
|
|
33
34
|
partitioned?: boolean | undefined | undefined;
|
|
34
|
-
name?: string | undefined;
|
|
35
35
|
};
|
|
36
36
|
alternateLinks?: boolean;
|
|
37
37
|
localeDetection?: boolean;
|
|
@@ -46,6 +46,7 @@ declare const routing: {
|
|
|
46
46
|
localePrefix?: next_intl_routing.LocalePrefix<string[], "always" | "as-needed" | "never"> | undefined;
|
|
47
47
|
domains?: undefined;
|
|
48
48
|
localeCookie?: boolean | {
|
|
49
|
+
name?: string | undefined;
|
|
49
50
|
maxAge?: number | undefined | undefined;
|
|
50
51
|
priority?: "low" | "medium" | "high" | undefined | undefined;
|
|
51
52
|
domain?: string | undefined | undefined;
|
|
@@ -53,7 +54,6 @@ declare const routing: {
|
|
|
53
54
|
secure?: boolean | undefined | undefined;
|
|
54
55
|
sameSite?: true | false | "lax" | "strict" | "none" | undefined | undefined;
|
|
55
56
|
partitioned?: boolean | undefined | undefined;
|
|
56
|
-
name?: string | undefined;
|
|
57
57
|
};
|
|
58
58
|
alternateLinks?: boolean;
|
|
59
59
|
localeDetection?: boolean;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@djangocfg/nextjs",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.604",
|
|
4
4
|
"description": "Next.js server utilities: sitemap, health, OG images, contact forms, navigation, config",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"nextjs",
|
|
@@ -59,6 +59,11 @@
|
|
|
59
59
|
"import": "./dist/config/index.mjs",
|
|
60
60
|
"default": "./dist/config/index.mjs"
|
|
61
61
|
},
|
|
62
|
+
"./auth": {
|
|
63
|
+
"types": "./dist/auth/index.d.mts",
|
|
64
|
+
"import": "./dist/auth/index.mjs",
|
|
65
|
+
"default": "./dist/auth/index.mjs"
|
|
66
|
+
},
|
|
62
67
|
"./ai": {
|
|
63
68
|
"types": "./dist/ai/index.d.mts",
|
|
64
69
|
"import": "./dist/ai/index.mjs",
|
|
@@ -154,10 +159,10 @@
|
|
|
154
159
|
"ai-docs": "tsx src/ai/cli.ts"
|
|
155
160
|
},
|
|
156
161
|
"peerDependencies": {
|
|
157
|
-
"@djangocfg/api": "^2.1.
|
|
158
|
-
"@djangocfg/devtools": "^2.1.
|
|
159
|
-
"@djangocfg/i18n": "^2.1.
|
|
160
|
-
"@djangocfg/ui-core": "^2.1.
|
|
162
|
+
"@djangocfg/api": "^2.1.604",
|
|
163
|
+
"@djangocfg/devtools": "^2.1.604",
|
|
164
|
+
"@djangocfg/i18n": "^2.1.604",
|
|
165
|
+
"@djangocfg/ui-core": "^2.1.604",
|
|
161
166
|
"next": "^16.2.2"
|
|
162
167
|
},
|
|
163
168
|
"peerDependenciesMeta": {
|
|
@@ -179,12 +184,12 @@
|
|
|
179
184
|
"semver": "^7.8.5"
|
|
180
185
|
},
|
|
181
186
|
"devDependencies": {
|
|
182
|
-
"@djangocfg/api": "^2.1.
|
|
183
|
-
"@djangocfg/devtools": "^2.1.
|
|
184
|
-
"@djangocfg/i18n": "^2.1.
|
|
185
|
-
"@djangocfg/layouts": "^2.1.
|
|
186
|
-
"@djangocfg/typescript-config": "^2.1.
|
|
187
|
-
"@djangocfg/ui-core": "^2.1.
|
|
187
|
+
"@djangocfg/api": "^2.1.604",
|
|
188
|
+
"@djangocfg/devtools": "^2.1.604",
|
|
189
|
+
"@djangocfg/i18n": "^2.1.604",
|
|
190
|
+
"@djangocfg/layouts": "^2.1.604",
|
|
191
|
+
"@djangocfg/typescript-config": "^2.1.604",
|
|
192
|
+
"@djangocfg/ui-core": "^2.1.604",
|
|
188
193
|
"@types/node": "^25.9.5",
|
|
189
194
|
"@types/react": "19.2.15",
|
|
190
195
|
"@types/react-dom": "19.2.3",
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server-side view of the shared session cookie.
|
|
3
|
+
*
|
|
4
|
+
* `@djangocfg/api` keeps the JWT pair in cookies on the registrable domain, so a Server
|
|
5
|
+
* Component, route handler or `generateMetadata` on any subdomain sees the same session
|
|
6
|
+
* with no setup:
|
|
7
|
+
*
|
|
8
|
+
* ```ts
|
|
9
|
+
* import { serverAuthHeaders } from '@djangocfg/nextjs/auth';
|
|
10
|
+
* const res = await fetch(`${API}/cfg/accounts/profile/`, { headers: await serverAuthHeaders() });
|
|
11
|
+
* ```
|
|
12
|
+
*
|
|
13
|
+
* The API authenticates the `Authorization` header only; this cookie is never an
|
|
14
|
+
* authenticator by itself, so reading it here creates no CSRF surface.
|
|
15
|
+
*/
|
|
16
|
+
import { cookies } from 'next/headers';
|
|
17
|
+
import { CFG_KEYS } from '@djangocfg/api/storage';
|
|
18
|
+
|
|
19
|
+
async function readSessionCookie(name: string): Promise<string | null> {
|
|
20
|
+
try {
|
|
21
|
+
const raw = (await cookies()).get(name)?.value;
|
|
22
|
+
return raw ? decodeURIComponent(raw) : null;
|
|
23
|
+
} catch {
|
|
24
|
+
// Outside a request scope (build time, static generation): no session.
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** The access token of the signed-in user, or `null`. May be expired: the API decides. */
|
|
30
|
+
export function getServerAccessToken(): Promise<string | null> {
|
|
31
|
+
return readSessionCookie(CFG_KEYS.accessToken.key);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** The refresh token, or `null`. Rarely needed on the server. */
|
|
35
|
+
export function getServerRefreshToken(): Promise<string | null> {
|
|
36
|
+
return readSessionCookie(CFG_KEYS.refreshToken.key);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** `{ Authorization: 'Bearer …' }` for a server-side fetch; `{}` when signed out. */
|
|
40
|
+
export async function serverAuthHeaders(): Promise<Record<string, string>> {
|
|
41
|
+
const token = await getServerAccessToken();
|
|
42
|
+
return token ? { Authorization: `Bearer ${token}` } : {};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Whether a session cookie is present (not whether it is still valid). */
|
|
46
|
+
export async function hasServerSession(): Promise<boolean> {
|
|
47
|
+
return (await getServerAccessToken()) !== null || (await getServerRefreshToken()) !== null;
|
|
48
|
+
}
|