@zitadel/sdk-next 0.1.0-alpha.9 → 0.1.0

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.
Files changed (48) hide show
  1. package/README.md +207 -37
  2. package/dist/auth.d.ts +66 -13
  3. package/dist/auth.d.ts.map +1 -0
  4. package/dist/auth.js +162 -7
  5. package/dist/client.d.ts +27 -2
  6. package/dist/client.d.ts.map +1 -0
  7. package/dist/client.js +29 -9
  8. package/dist/components.d.ts +16 -0
  9. package/dist/components.d.ts.map +1 -0
  10. package/dist/components.js +15 -0
  11. package/dist/context.d.ts +21 -10
  12. package/dist/context.d.ts.map +1 -0
  13. package/dist/context.js +24 -8
  14. package/dist/index.d.ts +16 -9
  15. package/dist/index.d.ts.map +1 -0
  16. package/dist/index.js +13 -24
  17. package/dist/jsx.d.ts +5 -0
  18. package/dist/lib/jwt.d.ts +9 -0
  19. package/dist/lib/jwt.d.ts.map +1 -0
  20. package/dist/lib/jwt.js +7 -0
  21. package/dist/middleware.d.ts +19 -11
  22. package/dist/middleware.d.ts.map +1 -0
  23. package/dist/middleware.js +304 -9
  24. package/dist/provider.d.ts +52 -0
  25. package/dist/provider.d.ts.map +1 -0
  26. package/dist/provider.js +75 -0
  27. package/dist/react.d.ts +26 -0
  28. package/dist/react.d.ts.map +1 -0
  29. package/dist/react.js +24 -0
  30. package/dist/server.d.ts +13 -2
  31. package/dist/server.d.ts.map +1 -0
  32. package/dist/server.js +10 -7
  33. package/dist/session.d.ts +77 -0
  34. package/dist/session.d.ts.map +1 -0
  35. package/dist/session.js +156 -0
  36. package/dist/types.d.ts +8 -3
  37. package/dist/types.d.ts.map +1 -0
  38. package/dist/types.js +1 -1
  39. package/dist/useAuth.d.ts +17 -5
  40. package/dist/useAuth.d.ts.map +1 -0
  41. package/dist/useAuth.js +18 -7
  42. package/package.json +46 -31
  43. package/dist/chunk-2BFQLJQE.js +0 -27
  44. package/dist/chunk-4KENHIG4.js +0 -222
  45. package/dist/chunk-6F4PWJZI.js +0 -0
  46. package/dist/chunk-B7S6XMT3.js +0 -41
  47. package/dist/chunk-OCZMYSFX.js +0 -13
  48. package/dist/chunk-XTCHTAIQ.js +0 -12
@@ -0,0 +1,52 @@
1
+ import "server-only";
2
+ import type { ReactNode } from "react";
3
+ import type { AuthResult, ClientAuthResult, ClientSession, NextgenSession } from "./types.js";
4
+ /**
5
+ * Seeds client components (the `useAuth()` hook) with the server-known auth
6
+ * state. Render it in a Server Component — typically the root layout — and
7
+ * pass the `auth()` result directly:
8
+ *
9
+ * ```tsx
10
+ * import { auth, NextgenProvider } from "@zitadel/sdk-next/server";
11
+ *
12
+ * export default async function RootLayout({ children }) {
13
+ * const session = await auth();
14
+ * return (
15
+ * <html>
16
+ * <body>
17
+ * <NextgenProvider session={session}>{children}</NextgenProvider>
18
+ * </body>
19
+ * </html>
20
+ * );
21
+ * }
22
+ * ```
23
+ *
24
+ * Executed in a Server Component, it converts the input to the client-safe
25
+ * {@link ClientAuthResult} — dropping the raw session token — and only the
26
+ * stripped value is serialised across the server→client boundary. Passing the
27
+ * full `auth()` result straight into a `"use client"` component would embed
28
+ * the raw token in the RSC flight payload, readable by any script running on
29
+ * the page. (sdk-nuxt strips the token before seeding client state for the
30
+ * same reason.)
31
+ *
32
+ * This module is **server-only, on purpose**. The strip only protects the
33
+ * boundary when it runs on the server: if this component could be imported
34
+ * into a `"use client"` wrapper (the common `providers.tsx` pattern), the
35
+ * *wrapper* would become the boundary and its still-unstripped `session`
36
+ * prop — token included — would serialise into the flight payload before
37
+ * this code ever ran. The `server-only` import turns that wrapper into a
38
+ * build error instead of a silent leak. For a client-seeded tree (e.g. state
39
+ * from `getSession()`), use `AuthContextProvider` from
40
+ * `@zitadel/sdk-next/react`, which only accepts the token-less
41
+ * {@link ClientAuthResult}.
42
+ *
43
+ * Client components therefore only ever see `userId` / `email` / `name`. When
44
+ * the raw token is needed server-side (e.g. to call an upstream API), read it
45
+ * from `auth()` in a Server Component or Route Handler — never through this
46
+ * provider.
47
+ */
48
+ export declare function NextgenProvider({ session, children, }: {
49
+ session: AuthResult | ClientAuthResult | ClientSession | NextgenSession | null;
50
+ children: ReactNode;
51
+ }): import("react/jsx-runtime").JSX.Element;
52
+ //# sourceMappingURL=provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.tsx"],"names":[],"mappings":"AAAA,OAAO,aAAa,CAAC;AAErB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,OAAO,KAAK,EACV,UAAU,EACV,gBAAgB,EAChB,aAAa,EACb,cAAc,EAEf,MAAM,YAAY,CAAC;AAmBpB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AACH,wBAAgB,eAAe,CAAC,EAC9B,OAAO,EACP,QAAQ,GACT,EAAE;IACD,OAAO,EAAE,UAAU,GAAG,gBAAgB,GAAG,aAAa,GAAG,cAAc,GAAG,IAAI,CAAC;IAC/E,QAAQ,EAAE,SAAS,CAAC;CACrB,2CAaA"}
@@ -0,0 +1,75 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import "server-only";
3
+ import { AuthContextProvider } from "./context.js";
4
+ const signedOut = { isAuthenticated: false, session: null };
5
+ /**
6
+ * Explicit field pick — never a spread. The raw session token (and any future
7
+ * server-only field) must not survive the conversion to the client shape.
8
+ */
9
+ function toClientSession(session) {
10
+ return {
11
+ userId: session.userId,
12
+ identifier: session.identifier,
13
+ identifierProperty: session.identifierProperty,
14
+ display: session.display,
15
+ };
16
+ }
17
+ /**
18
+ * Seeds client components (the `useAuth()` hook) with the server-known auth
19
+ * state. Render it in a Server Component — typically the root layout — and
20
+ * pass the `auth()` result directly:
21
+ *
22
+ * ```tsx
23
+ * import { auth, NextgenProvider } from "@zitadel/sdk-next/server";
24
+ *
25
+ * export default async function RootLayout({ children }) {
26
+ * const session = await auth();
27
+ * return (
28
+ * <html>
29
+ * <body>
30
+ * <NextgenProvider session={session}>{children}</NextgenProvider>
31
+ * </body>
32
+ * </html>
33
+ * );
34
+ * }
35
+ * ```
36
+ *
37
+ * Executed in a Server Component, it converts the input to the client-safe
38
+ * {@link ClientAuthResult} — dropping the raw session token — and only the
39
+ * stripped value is serialised across the server→client boundary. Passing the
40
+ * full `auth()` result straight into a `"use client"` component would embed
41
+ * the raw token in the RSC flight payload, readable by any script running on
42
+ * the page. (sdk-nuxt strips the token before seeding client state for the
43
+ * same reason.)
44
+ *
45
+ * This module is **server-only, on purpose**. The strip only protects the
46
+ * boundary when it runs on the server: if this component could be imported
47
+ * into a `"use client"` wrapper (the common `providers.tsx` pattern), the
48
+ * *wrapper* would become the boundary and its still-unstripped `session`
49
+ * prop — token included — would serialise into the flight payload before
50
+ * this code ever ran. The `server-only` import turns that wrapper into a
51
+ * build error instead of a silent leak. For a client-seeded tree (e.g. state
52
+ * from `getSession()`), use `AuthContextProvider` from
53
+ * `@zitadel/sdk-next/react`, which only accepts the token-less
54
+ * {@link ClientAuthResult}.
55
+ *
56
+ * Client components therefore only ever see `userId` / `email` / `name`. When
57
+ * the raw token is needed server-side (e.g. to call an upstream API), read it
58
+ * from `auth()` in a Server Component or Route Handler — never through this
59
+ * provider.
60
+ */
61
+ export function NextgenProvider({ session, children, }) {
62
+ let value;
63
+ if (!session) {
64
+ value = signedOut;
65
+ }
66
+ else if ("isAuthenticated" in session) {
67
+ value = session.isAuthenticated
68
+ ? { isAuthenticated: true, session: toClientSession(session.session) }
69
+ : signedOut;
70
+ }
71
+ else {
72
+ value = { isAuthenticated: true, session: toClientSession(session) };
73
+ }
74
+ return _jsx(AuthContextProvider, { value: value, children: children });
75
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Client-safe React bindings for `@zitadel/sdk-next`.
3
+ *
4
+ * This is the entry point for `"use client"` components. It pulls in no
5
+ * server-only modules (`next/headers`, `auth()`, `NextgenProvider`), so it is
6
+ * safe to import anywhere.
7
+ *
8
+ * ```tsx
9
+ * "use client";
10
+ * import { useAuth } from "@zitadel/sdk-next/react";
11
+ * ```
12
+ *
13
+ * `NextgenProvider` is deliberately **not** exported here: it accepts the
14
+ * token-bearing `auth()` result, so it must execute in a Server Component —
15
+ * wrapping it in a `"use client"` file would serialise the raw token across
16
+ * the boundary before the provider strips it. Import it from
17
+ * `@zitadel/sdk-next/server` (or the package root) instead; the `server-only`
18
+ * guard turns a client-side import into a build error. To seed the context
19
+ * from client-side state (e.g. a `getSession()` read), render
20
+ * {@link AuthContextProvider}, which only accepts the token-less
21
+ * `ClientAuthResult`.
22
+ */
23
+ export { AuthContextProvider, useAuthContext } from "./context.js";
24
+ export { useAuth } from "./useAuth.js";
25
+ export type { AuthResult, AuthState, ClientAuthResult, ClientAuthState, ClientSession, NextgenSession, UnauthState, } from "./types.js";
26
+ //# sourceMappingURL=react.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,YAAY,EACV,UAAU,EACV,SAAS,EACT,gBAAgB,EAChB,eAAe,EACf,aAAa,EACb,cAAc,EACd,WAAW,GACZ,MAAM,YAAY,CAAC"}
package/dist/react.js ADDED
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Client-safe React bindings for `@zitadel/sdk-next`.
3
+ *
4
+ * This is the entry point for `"use client"` components. It pulls in no
5
+ * server-only modules (`next/headers`, `auth()`, `NextgenProvider`), so it is
6
+ * safe to import anywhere.
7
+ *
8
+ * ```tsx
9
+ * "use client";
10
+ * import { useAuth } from "@zitadel/sdk-next/react";
11
+ * ```
12
+ *
13
+ * `NextgenProvider` is deliberately **not** exported here: it accepts the
14
+ * token-bearing `auth()` result, so it must execute in a Server Component —
15
+ * wrapping it in a `"use client"` file would serialise the raw token across
16
+ * the boundary before the provider strips it. Import it from
17
+ * `@zitadel/sdk-next/server` (or the package root) instead; the `server-only`
18
+ * guard turns a client-side import into a build error. To seed the context
19
+ * from client-side state (e.g. a `getSession()` read), render
20
+ * {@link AuthContextProvider}, which only accepts the token-less
21
+ * `ClientAuthResult`.
22
+ */
23
+ export { AuthContextProvider, useAuthContext } from "./context.js";
24
+ export { useAuth } from "./useAuth.js";
package/dist/server.d.ts CHANGED
@@ -1,2 +1,13 @@
1
- export { auth } from './auth.js';
2
- import '@zitadel/sdk-core/types';
1
+ /**
2
+ * Server-side surface of `@zitadel/sdk-next`: everything here is guarded by
3
+ * `server-only` and fails the build if pulled into a `"use client"` graph.
4
+ *
5
+ * ```tsx
6
+ * import { auth, NextgenProvider } from "@zitadel/sdk-next/server";
7
+ * ```
8
+ */
9
+ export { auth } from "./auth.js";
10
+ export type { AuthOptions } from "./auth.js";
11
+ export { NextgenProvider } from "./provider.js";
12
+ export type { AuthResult, AuthState, UnauthState, NextgenSession, ClientAuthResult, NextgenMiddlewareOptions, } from "./types.js";
13
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,YAAY,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,YAAY,EACV,UAAU,EACV,SAAS,EACT,WAAW,EACX,cAAc,EACd,gBAAgB,EAChB,wBAAwB,GACzB,MAAM,YAAY,CAAC"}
package/dist/server.js CHANGED
@@ -1,7 +1,10 @@
1
- import {
2
- auth
3
- } from "./chunk-B7S6XMT3.js";
4
- import "./chunk-OCZMYSFX.js";
5
- export {
6
- auth
7
- };
1
+ /**
2
+ * Server-side surface of `@zitadel/sdk-next`: everything here is guarded by
3
+ * `server-only` and fails the build if pulled into a `"use client"` graph.
4
+ *
5
+ * ```tsx
6
+ * import { auth, NextgenProvider } from "@zitadel/sdk-next/server";
7
+ * ```
8
+ */
9
+ export { auth } from "./auth.js";
10
+ export { NextgenProvider } from "./provider.js";
@@ -0,0 +1,77 @@
1
+ import type { ClientAuthResult } from "./types.js";
2
+ /** Options for {@link getSession}. */
3
+ export type GetSessionOptions = {
4
+ /**
5
+ * Proxy path the scaffolded request boundary forwards to the Zitadel
6
+ * backend. Defaults to the path from `configureZitadel()` when it has run
7
+ * on this page, else `"/__nextgen"` (the scaffold default).
8
+ */
9
+ proxyPath?: string;
10
+ /**
11
+ * The project this app signs its users in to. A session of another project
12
+ * reads as signed out. Defaults to the project from `configureZitadel()`
13
+ * when it has run on this page, else `NEXT_PUBLIC_ZITADEL_PROJECT_ID`. With
14
+ * none, nobody reads as signed in, as on the server.
15
+ */
16
+ projectId?: string;
17
+ };
18
+ /**
19
+ * Reads the current session state from the browser — the supported way for
20
+ * an app's own UI (header navigation, account menus) to know whether a user
21
+ * is signed in and who they are.
22
+ *
23
+ * Fetches the same-origin `{proxyPath}/sessions/me?project_id=…` with
24
+ * credentials and `cache: "no-store"` — the same read the `<zitadel-session>`
25
+ * card performs — so the answer is the server's, not a client-side guess.
26
+ * Works on any page: unlike server-side `auth()`, it does not require the
27
+ * route to be covered by the middleware `matcher` (only the proxy path itself
28
+ * must be matched, which the scaffolded request boundary always does).
29
+ *
30
+ * A session counts only in the app's own project: `options.projectId`, else
31
+ * the project of `configureZitadel()`, else `NEXT_PUBLIC_ZITADEL_PROJECT_ID`.
32
+ * With none of them, it reads as signed out without asking the server.
33
+ *
34
+ * - `200` with an authenticated user → `{ isAuthenticated: true, session }`
35
+ * with the client-safe identity (`userId`, `email`, `name` — no token).
36
+ * - `200` for an anonymous session, `401` with `auth.unauthorized`, `403`
37
+ * with `sess.project_mismatch`, or `404` with `sess.not_found` → signed out.
38
+ * The `403` answers a session of another project on the same server, and a
39
+ * `200` naming another project (from a server that predates the parameter)
40
+ * reads as signed out too.
41
+ * - Any other response throws — including a framework's HTML 404 page from
42
+ * a misrouted proxy: a failing proxy is a misconfiguration and must not
43
+ * silently render as "signed out". Treat a rejection as "unknown" —
44
+ * distinct from signed-out — as the example does.
45
+ *
46
+ * ```tsx
47
+ * "use client";
48
+ * import { getSession, type ClientAuthResult } from "@zitadel/sdk-next/session";
49
+ *
50
+ * export function HeaderNav() {
51
+ * // undefined = not yet known — render neutral chrome, not "Sign in".
52
+ * const [auth, setAuth] = useState<ClientAuthResult>();
53
+ * const [failed, setFailed] = useState(false);
54
+ * useEffect(() => {
55
+ * getSession({ projectId: process.env.NEXT_PUBLIC_ZITADEL_PROJECT_ID }).then(
56
+ * setAuth,
57
+ * () => setFailed(true),
58
+ * );
59
+ * }, []);
60
+ * if (failed) return <span role="alert">Session unavailable</span>;
61
+ * if (!auth) return null;
62
+ * return auth.isAuthenticated
63
+ * ? <a href="/profile">{auth.session.display ?? auth.session.identifier ?? "Account"}</a>
64
+ * : <a href="/login">Sign in</a>;
65
+ * }
66
+ * ```
67
+ *
68
+ * The transitions need no extra wiring in the scaffolded posture: sign-in
69
+ * (`post-sign-in-url`) and sign-out (`post-sign-out-url`) both navigate, so
70
+ * chrome re-reads on the next page load. To react in place instead, listen
71
+ * for the widgets' `zitadel-signout` / `zitadel-flow-complete` events.
72
+ *
73
+ * @returns The current {@link ClientAuthResult}.
74
+ */
75
+ export declare function getSession(options?: GetSessionOptions): Promise<ClientAuthResult>;
76
+ export type { ClientAuthResult, ClientAuthState, ClientSession } from "./types.js";
77
+ //# sourceMappingURL=session.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAKnD,sCAAsC;AACtC,MAAM,MAAM,iBAAiB,GAAG;IAC9B;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AA8BF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDG;AACH,wBAAsB,UAAU,CAAC,OAAO,GAAE,iBAAsB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAqE3F;AAED,YAAY,EAAE,gBAAgB,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,156 @@
1
+ import { getZitadelConfig } from "@zitadel/api/config";
2
+ /** Matches the `configureZitadel()` default so zero-config apps agree with the scaffold. */
3
+ const DEFAULT_PROXY_PATH = "/__nextgen";
4
+ /**
5
+ * `NEXT_PUBLIC_ZITADEL_PROJECT_ID`, which Next.js inlines into client bundles
6
+ * at build time. Read defensively: where it was not inlined, `process` may not
7
+ * exist in the browser.
8
+ */
9
+ function publicProjectId() {
10
+ try {
11
+ return process.env.NEXT_PUBLIC_ZITADEL_PROJECT_ID || undefined;
12
+ }
13
+ catch {
14
+ return undefined;
15
+ }
16
+ }
17
+ let warnedMissingProject = false;
18
+ /** Says once per page why `getSession()` signs no one in: no project is known. */
19
+ function warnMissingProject() {
20
+ if (warnedMissingProject) {
21
+ return;
22
+ }
23
+ warnedMissingProject = true;
24
+ console.warn("[nextgen] getSession(): no project id is known, so no session counts as signed in. " +
25
+ "Pass `projectId` (e.g. process.env.NEXT_PUBLIC_ZITADEL_PROJECT_ID) or call " +
26
+ "configureZitadel() first.");
27
+ }
28
+ /**
29
+ * Reads the current session state from the browser — the supported way for
30
+ * an app's own UI (header navigation, account menus) to know whether a user
31
+ * is signed in and who they are.
32
+ *
33
+ * Fetches the same-origin `{proxyPath}/sessions/me?project_id=…` with
34
+ * credentials and `cache: "no-store"` — the same read the `<zitadel-session>`
35
+ * card performs — so the answer is the server's, not a client-side guess.
36
+ * Works on any page: unlike server-side `auth()`, it does not require the
37
+ * route to be covered by the middleware `matcher` (only the proxy path itself
38
+ * must be matched, which the scaffolded request boundary always does).
39
+ *
40
+ * A session counts only in the app's own project: `options.projectId`, else
41
+ * the project of `configureZitadel()`, else `NEXT_PUBLIC_ZITADEL_PROJECT_ID`.
42
+ * With none of them, it reads as signed out without asking the server.
43
+ *
44
+ * - `200` with an authenticated user → `{ isAuthenticated: true, session }`
45
+ * with the client-safe identity (`userId`, `email`, `name` — no token).
46
+ * - `200` for an anonymous session, `401` with `auth.unauthorized`, `403`
47
+ * with `sess.project_mismatch`, or `404` with `sess.not_found` → signed out.
48
+ * The `403` answers a session of another project on the same server, and a
49
+ * `200` naming another project (from a server that predates the parameter)
50
+ * reads as signed out too.
51
+ * - Any other response throws — including a framework's HTML 404 page from
52
+ * a misrouted proxy: a failing proxy is a misconfiguration and must not
53
+ * silently render as "signed out". Treat a rejection as "unknown" —
54
+ * distinct from signed-out — as the example does.
55
+ *
56
+ * ```tsx
57
+ * "use client";
58
+ * import { getSession, type ClientAuthResult } from "@zitadel/sdk-next/session";
59
+ *
60
+ * export function HeaderNav() {
61
+ * // undefined = not yet known — render neutral chrome, not "Sign in".
62
+ * const [auth, setAuth] = useState<ClientAuthResult>();
63
+ * const [failed, setFailed] = useState(false);
64
+ * useEffect(() => {
65
+ * getSession({ projectId: process.env.NEXT_PUBLIC_ZITADEL_PROJECT_ID }).then(
66
+ * setAuth,
67
+ * () => setFailed(true),
68
+ * );
69
+ * }, []);
70
+ * if (failed) return <span role="alert">Session unavailable</span>;
71
+ * if (!auth) return null;
72
+ * return auth.isAuthenticated
73
+ * ? <a href="/profile">{auth.session.display ?? auth.session.identifier ?? "Account"}</a>
74
+ * : <a href="/login">Sign in</a>;
75
+ * }
76
+ * ```
77
+ *
78
+ * The transitions need no extra wiring in the scaffolded posture: sign-in
79
+ * (`post-sign-in-url`) and sign-out (`post-sign-out-url`) both navigate, so
80
+ * chrome re-reads on the next page load. To react in place instead, listen
81
+ * for the widgets' `zitadel-signout` / `zitadel-flow-complete` events.
82
+ *
83
+ * @returns The current {@link ClientAuthResult}.
84
+ */
85
+ export async function getSession(options = {}) {
86
+ if (typeof window === "undefined") {
87
+ throw new Error("[nextgen] getSession() reads the session from the browser. " +
88
+ "In Server Components and Route Handlers use auth() from @zitadel/sdk-next/server " +
89
+ "(requires the route to be covered by the middleware matcher).");
90
+ }
91
+ // Strip trailing slashes so "/__nextgen/" doesn't produce a double-slash
92
+ // URL that misses the request-boundary matcher — same normalization the
93
+ // typed API client applies to its base URL.
94
+ let proxyPath = options.proxyPath ?? getZitadelConfig()?.proxyPath ?? DEFAULT_PROXY_PATH;
95
+ while (proxyPath.endsWith("/")) {
96
+ proxyPath = proxyPath.slice(0, -1);
97
+ }
98
+ const projectId = options.projectId || getZitadelConfig()?.projectId || publicProjectId();
99
+ if (!projectId) {
100
+ warnMissingProject();
101
+ return { isAuthenticated: false, session: null };
102
+ }
103
+ const response = await fetch(`${proxyPath}/sessions/me?project_id=${encodeURIComponent(projectId)}`, {
104
+ cache: "no-store",
105
+ credentials: "include",
106
+ headers: { accept: "application/json" },
107
+ });
108
+ // Only the backend's canonical error envelope is definitive signed-out.
109
+ // A framework route, gateway, or WAF can also return 401/404; accepting the
110
+ // status or content type alone would turn a broken proxy into signed-out.
111
+ if (response.status === 401 || response.status === 403 || response.status === 404) {
112
+ const error = await readErrorEnvelope(response);
113
+ const isSignedOut = (response.status === 401 && error?.code === "auth.unauthorized") ||
114
+ (response.status === 403 && error?.code === "sess.project_mismatch") ||
115
+ (response.status === 404 && error?.code === "sess.not_found");
116
+ if (isSignedOut) {
117
+ return { isAuthenticated: false, session: null };
118
+ }
119
+ }
120
+ if (!response.ok) {
121
+ throw new Error(`[nextgen] Session read failed: HTTP ${response.status} from ${proxyPath}/sessions/me`);
122
+ }
123
+ const session = (await response.json());
124
+ // An anonymous session (no verified user factor yet) has no user_id, and a
125
+ // backend that predates `project_id` answers for any project: for app
126
+ // chrome, either is "not signed in".
127
+ if (!session.user_id || session.project_id !== projectId) {
128
+ return { isAuthenticated: false, session: null };
129
+ }
130
+ return {
131
+ isAuthenticated: true,
132
+ session: {
133
+ userId: session.user_id,
134
+ identifier: session.user?.identifier ?? null,
135
+ identifierProperty: session.user?.identifier_property ?? null,
136
+ display: session.user?.display ?? null,
137
+ },
138
+ };
139
+ }
140
+ async function readErrorEnvelope(response) {
141
+ try {
142
+ const body = (await response.json());
143
+ if (typeof body === "object" &&
144
+ body !== null &&
145
+ "code" in body &&
146
+ typeof body.code === "string" &&
147
+ "message" in body &&
148
+ typeof body.message === "string") {
149
+ return { code: body.code, message: body.message };
150
+ }
151
+ }
152
+ catch {
153
+ // The caller reports the HTTP failure below; parsing details are untrusted.
154
+ }
155
+ return undefined;
156
+ }
package/dist/types.d.ts CHANGED
@@ -1,3 +1,8 @@
1
- export { AuthResult, AuthState, NextgenMiddlewareOptions, NextgenSession, UnauthState } from '@zitadel/sdk-core/types';
2
- import '@zitadel/components';
3
- import '@zitadel/api/config';
1
+ /**
2
+ * Re-exports shared SDK types from `@zitadel/sdk-core`.
3
+ *
4
+ * These types are defined once in sdk-core and shared by both sdk-next
5
+ * and sdk-nuxt.
6
+ */
7
+ export type { NextgenSession, AuthState, UnauthState, AuthResult, NextgenMiddlewareOptions, ClientSession, ClientAuthState, ClientAuthResult, } from "@zitadel/sdk-core/middleware";
8
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,YAAY,EACV,cAAc,EACd,SAAS,EACT,WAAW,EACX,UAAU,EACV,wBAAwB,EAGxB,aAAa,EACb,eAAe,EACf,gBAAgB,GACjB,MAAM,8BAA8B,CAAC"}
package/dist/types.js CHANGED
@@ -1 +1 @@
1
- import "./chunk-6F4PWJZI.js";
1
+ export {};
package/dist/useAuth.d.ts CHANGED
@@ -1,5 +1,17 @@
1
- import { AuthResult } from '@zitadel/sdk-core/types';
2
-
3
- declare function useAuth(): AuthResult;
4
-
5
- export { useAuth };
1
+ import type { ClientAuthResult } from "./types.js";
2
+ /**
3
+ * Reads the auth state seeded by {@link NextgenProvider} in a client
4
+ * component.
5
+ *
6
+ * Returns the client-safe {@link ClientAuthResult} (`userId` / `email` /
7
+ * `name`) — the raw session token is stripped server-side by the provider
8
+ * and is never available client-side. This is the same shape sdk-nuxt's
9
+ * `useAuth()` and `getSession()` return.
10
+ *
11
+ * The value reflects what the server knew when the page rendered. For chrome
12
+ * on pages outside the middleware `matcher` (where `auth()` reports signed
13
+ * out), read the session live with `getSession()` from
14
+ * `@zitadel/sdk-next/session` instead.
15
+ */
16
+ export declare function useAuth(): ClientAuthResult;
17
+ //# sourceMappingURL=useAuth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useAuth.d.ts","sourceRoot":"","sources":["../src/useAuth.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAInD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,OAAO,IAAI,gBAAgB,CAE1C"}
package/dist/useAuth.js CHANGED
@@ -1,8 +1,19 @@
1
1
  "use client";
2
- import {
3
- useAuth
4
- } from "./chunk-XTCHTAIQ.js";
5
- import "./chunk-2BFQLJQE.js";
6
- export {
7
- useAuth
8
- };
2
+ import { useAuthContext } from "./context.js";
3
+ /**
4
+ * Reads the auth state seeded by {@link NextgenProvider} in a client
5
+ * component.
6
+ *
7
+ * Returns the client-safe {@link ClientAuthResult} (`userId` / `email` /
8
+ * `name`) — the raw session token is stripped server-side by the provider
9
+ * and is never available client-side. This is the same shape sdk-nuxt's
10
+ * `useAuth()` and `getSession()` return.
11
+ *
12
+ * The value reflects what the server knew when the page rendered. For chrome
13
+ * on pages outside the middleware `matcher` (where `auth()` reports signed
14
+ * out), read the session live with `getSession()` from
15
+ * `@zitadel/sdk-next/session` instead.
16
+ */
17
+ export function useAuth() {
18
+ return useAuthContext();
19
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zitadel/sdk-next",
3
- "version": "0.1.0-alpha.9",
3
+ "version": "0.1.0",
4
4
  "description": "Next.js helpers and mock auth UI for Zitadel",
5
5
  "homepage": "https://github.com/zitadel/nextgen/tree/main/packages/sdk-next#readme",
6
6
  "bugs": {
@@ -16,6 +16,12 @@
16
16
  "dist"
17
17
  ],
18
18
  "type": "module",
19
+ "sideEffects": [
20
+ "./dist/client.js",
21
+ "./dist/components.js",
22
+ "./dist/auth.js",
23
+ "./dist/provider.js"
24
+ ],
19
25
  "exports": {
20
26
  ".": {
21
27
  "types": "./dist/index.d.ts",
@@ -29,54 +35,63 @@
29
35
  "types": "./dist/client.d.ts",
30
36
  "import": "./dist/client.js"
31
37
  },
38
+ "./components": {
39
+ "types": "./dist/components.d.ts",
40
+ "import": "./dist/components.js"
41
+ },
42
+ "./react": {
43
+ "types": "./dist/react.d.ts",
44
+ "import": "./dist/react.js"
45
+ },
32
46
  "./middleware": {
33
47
  "types": "./dist/middleware.d.ts",
34
48
  "import": "./dist/middleware.js"
49
+ },
50
+ "./jsx": {
51
+ "types": "./dist/jsx.d.ts"
52
+ },
53
+ "./session": {
54
+ "types": "./dist/session.d.ts",
55
+ "import": "./dist/session.js"
35
56
  }
36
57
  },
37
58
  "publishConfig": {
38
59
  "access": "public"
39
60
  },
40
61
  "dependencies": {
62
+ "@zitadel/api": "0.1.0",
63
+ "@zitadel/components": "0.1.0",
64
+ "@zitadel/sdk-core": "0.1.0",
65
+ "@zitadel/sdk-react": "0.1.0",
41
66
  "server-only": "^0.0.1",
42
- "@zitadel/api": "0.1.0-alpha.9",
43
- "@zitadel/components": "0.1.0-alpha.9",
44
- "@zitadel/sdk-core": "0.1.0-alpha.9"
67
+ "ufo": "^1.6.4"
45
68
  },
46
69
  "peerDependencies": {
47
- "next": ">=14",
70
+ "next": ">=15.2.3",
48
71
  "react": ">=18",
49
72
  "react-dom": ">=18"
50
73
  },
51
74
  "devDependencies": {
52
- "@eslint/js": "^9.0.0",
53
- "tsup": "^8.3.5",
54
- "typescript": "^5.7.3",
55
- "@eslint/json": "^0.11.0",
56
- "@eslint/markdown": "^6.0.0",
57
- "@testing-library/react": "^16.0.0",
58
- "@testing-library/user-event": "^14.0.0",
75
+ "@edge-runtime/vm": "^5.0.0",
76
+ "@testing-library/react": "^16.3.2",
77
+ "@testing-library/user-event": "^14.6.1",
78
+ "@types/node": "^24.19.1",
59
79
  "@types/react": "^19.2.14",
60
- "eslint": "^9.0.0",
61
- "eslint-config-prettier": "^10.0.0",
62
- "eslint-import-resolver-typescript": "^3.7.0",
63
- "eslint-plugin-import": "^2.31.0",
64
- "eslint-plugin-jsx-a11y": "^6.10.0",
65
- "eslint-plugin-perfectionist": "^4.0.0",
66
- "eslint-plugin-prettier": "^5.0.0",
67
- "eslint-plugin-react": "^7.37.0",
68
- "eslint-plugin-react-hooks": "^5.0.0",
69
- "eslint-plugin-testing-library": "^7.0.0",
70
- "jsdom": "^26.0.0",
71
- "next": "^16.2.4",
72
- "prettier": "^3.0.0",
73
- "typescript-eslint": "^8.0.0",
74
- "vitest": "^3.0.0"
80
+ "@types/react-dom": "^19.2.3",
81
+ "@vitest/coverage-v8": "^4.1.11",
82
+ "jsdom": "^29.0.2",
83
+ "next": "^16.3.8",
84
+ "react": "^19.2.8",
85
+ "react-dom": "^19.2.8",
86
+ "typescript": "^6.0.3",
87
+ "vitest": "^4.1.11"
75
88
  },
76
89
  "scripts": {
77
- "build": "tsup src/middleware.ts src/auth.ts src/context.tsx src/useAuth.ts src/types.ts src/index.ts src/server.ts src/client.ts --format esm --dts --clean --tsconfig tsconfig.build.json",
78
- "typecheck": "tsc --noEmit",
79
- "test": "vitest run --passWithNoTests",
80
- "lint": "eslint ."
90
+ "build": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\" && tsc -p tsconfig.build.json && node -e \"require('node:fs').copyFileSync('src/jsx.d.ts', 'dist/jsx.d.ts')\"",
91
+ "typecheck": "tsc --noEmit -p tsconfig.lib.json && tsc --noEmit -p tsconfig.spec.json",
92
+ "test": "vitest run",
93
+ "test:all": "pnpm run test",
94
+ "lint": "biome check .",
95
+ "build-release": "node ../../scripts/release-clean.mjs local-dist && pnpm run build"
81
96
  }
82
97
  }