Skip to content
This repository was archived by the owner on Sep 24, 2025. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions demos/nextjs-ssr-demo/src/app/guarded-csr/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
"use client";

import { createNhostClient } from "../lib/nhost/client";
import Link from "next/link";

export default function GuardedCSRPage() {
const nhost = createNhostClient();
const session = nhost.getUserSession();

const { accessToken } = session || {};
const isAuthenticated = !!session;

return (
<div className="flex flex-col">
<h1 className="text-3xl mb-6 gradient-text">Guarded Client-side Page</h1>
<p className="mb-4">
This page is rendered client-side and is protected by middleware. You
should only see this if you are authenticated.
</p>

<div className="glass-card p-6 mb-6">
<h2 className="text-xl font-semibold mb-2">Authentication Status</h2>
<div className="profile-item">
<strong>Access Token (from client hook):</strong>
<div className="profile-item">
<strong>User Authenticated:</strong>
<span className="ml-2">{isAuthenticated ? "Yes" : "No"}</span>
</div>
<div className="profile-item mt-2">
<strong>Access Token:</strong>
<pre
className="mt-1 p-2 bg-gray-800 rounded text-xs break-all"
style={{ fontFamily: "var(--font-geist-mono)" }}
>
{accessToken || "Not available or not authenticated"}
</pre>
</div>
</div>
</div>

<Link href="/" className="text-blue-500 hover:underline">
← Back to Home
</Link>
</div>
);
}
35 changes: 35 additions & 0 deletions demos/nextjs-ssr-demo/src/app/guarded-ssr/GuardedSSRClientInfo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
"use client";

import { createNhostClient } from "../lib/nhost/client";

export default function GuardedSSRClientInfo({
initialAccessToken,
}: {
initialAccessToken?: string;
}) {
const nhost = createNhostClient();
const session = nhost.getUserSession();

const { accessToken } = session || {};

return (
<div className="glass-card p-6">
<h2 className="text-xl font-semibold mb-2">
Client-Side Hook Info (on SSR Page)
</h2>
<div className="profile-item">
<strong>Access Token (from client hook):</strong>
<pre
className="mt-1 p-2 bg-gray-800 rounded text-xs break-all"
style={{ fontFamily: "var(--font-geist-mono)" }}
>
{accessToken || "Loading or not available..."}
</pre>
</div>
<p className="text-xs mt-2 text-gray-400">
(Server initially provided an access token:{" "}
{initialAccessToken ? "Yes" : "No"})
</p>
</div>
);
}
52 changes: 52 additions & 0 deletions demos/nextjs-ssr-demo/src/app/guarded-ssr/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { createNhostClient } from "../lib/nhost/server"; // Adjust path if needed
import Link from "next/link";
import GuardedSSRClientInfo from "./GuardedSSRClientInfo"; // We'll create this

export default async function GuardedSSRPage() {
const nhost = await createNhostClient();
const session = nhost.getUserSession();

// Middleware should have already redirected if no session,
// but good practice to check if data is used.
// For this page, we primarily demonstrate SSR access to the token.

return (
<div className="flex flex-col">
<h1 className="text-3xl mb-6 gradient-text">Guarded Server-side Page</h1>
<p className="mb-4">
This page is primarily rendered server-side and is protected by
middleware. You should only see this if you are authenticated.
</p>

<div className="glass-card p-6 mb-6">
<h2 className="text-xl font-semibold mb-2">Server-Side Session Info</h2>
<div className="profile-item">
<strong>Access Token (from server):</strong>
<pre
className="mt-1 p-2 bg-gray-800 rounded text-xs break-all"
style={{ fontFamily: "var(--font-geist-mono)" }}
>
{session?.accessToken ||
"Not available (should not happen on guarded route)"}
</pre>
</div>
<div className="profile-item mt-2">
<strong>User ID (from server):</strong>
<span
className="ml-2"
style={{ fontFamily: "var(--font-geist-mono)" }}
>
{session?.user?.id || "Not available"}
</span>
</div>
</div>

{/* Optional: Demonstrate client-side hooks */}
<GuardedSSRClientInfo initialAccessToken={session?.accessToken} />

<Link href="/" className="mt-6 text-blue-500 hover:underline">
← Back to Home
</Link>
</div>
);
}
45 changes: 45 additions & 0 deletions demos/nextjs-ssr-demo/src/app/public-csr/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
"use client";

import { createNhostClient } from "../lib/nhost/client";
import Link from "next/link";

export default function PublicCSRPage() {
const nhost = createNhostClient();
const session = nhost.getUserSession();

const { accessToken } = session || {};
const isAuthenticated = !!session;

return (
<div className="flex flex-col">
<h1 className="text-3xl mb-6 gradient-text">Public Client-side Page</h1>
<p className="mb-4">
This page is rendered client-side and is public. It shows auth state if
available.
</p>

<div className="glass-card p-6 mb-6">
<h2 className="text-xl font-semibold mb-2">
Authentication Status (Client Hooks)
</h2>
<div className="profile-item">
<strong>User Authenticated:</strong>
<span className="ml-2">{isAuthenticated ? "Yes" : "No"}</span>
</div>
<div className="profile-item mt-2">
<strong>Access Token:</strong>
<pre
className="mt-1 p-2 bg-gray-800 rounded text-xs break-all"
style={{ fontFamily: "var(--font-geist-mono)" }}
>
{accessToken || "Not available or not authenticated"}
</pre>
</div>
</div>

<Link href="/" className="text-blue-500 hover:underline">
← Back to Home
</Link>
</div>
);
}
56 changes: 56 additions & 0 deletions demos/nextjs-ssr-demo/src/app/public-ssr/PublicSSRClientInfo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
"use client";

import { createNhostClient } from "../lib/nhost/client";

interface Props {
initialIsAuthenticated: boolean;
initialAccessToken?: string;
}

export default function PublicSSRClientInfo({
initialIsAuthenticated,
initialAccessToken,
}: Props) {
const nhost = createNhostClient();
// FIXME: use hooks, bc throws error
// ⨯ ReferenceError: document is not defined
// at CookieStorage.get (../../packages/nhost-js/src/sessionStorage.ts:152:20)
// at NhostClient.getUserSession (../../packages/nhost-js/src/index.ts:233:31)
// at PublicSSRClientInfo (src/app/public-ssr/PublicSSRClientInfo.tsx:15:24)
// 150 | */
// 151 | get(): Session | null {
// > 152 | const cookies = document.cookie.split(";");
// | ^
// 153 | for (const cookie of cookies) {
// 154 | const [name, value] = cookie.trim().split("=");
// 155 | if (name === this.cookieName) { {
const session = nhost.getUserSession();

const { accessToken } = session || {};

return (
<div className="glass-card p-6">
<h2 className="text-xl font-semibold mb-2">
Client-Side Hook Info (on Public SSR Page)
</h2>
<div className="profile-item">
<strong>User Authenticated (from client hook):</strong>
<span className="ml-2">{session ? "Yes" : "No"}</span>
</div>
<div className="profile-item mt-2">
<strong>Access Token (from client hook):</strong>
<pre
className="mt-1 p-2 bg-gray-800 rounded text-xs break-all"
style={{ fontFamily: "var(--font-geist-mono)" }}
>
{accessToken || "Not available or not authenticated"}
</pre>
</div>
<p className="text-xs mt-2 text-gray-400">
(Server initially reported authenticated:{" "}
{initialIsAuthenticated ? "Yes" : "No"}, and token:{" "}
{initialAccessToken ? "Exists" : "Absent"})
</p>
</div>
);
}
46 changes: 46 additions & 0 deletions demos/nextjs-ssr-demo/src/app/public-ssr/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { createNhostClient } from "../lib/nhost/server";
import Link from "next/link";
import PublicSSRClientInfo from "./PublicSSRClientInfo"; // We'll create this

export default async function PublicSSRPage() {
const nhost = await createNhostClient();
const session = nhost.getUserSession();
const isAuthenticatedOnServer = !!session;

return (
<div className="flex flex-col">
<h1 className="text-3xl mb-6 gradient-text">Public Server-side Page</h1>
<p className="mb-4">
This page is primarily rendered server-side and is public. It shows auth
state if available.
</p>

<div className="glass-card p-6 mb-6">
<h2 className="text-xl font-semibold mb-2">Server-Side Session Info</h2>
<div className="profile-item">
<strong>User Authenticated (on server):</strong>
<span className="ml-2">{isAuthenticatedOnServer ? "Yes" : "No"}</span>
</div>
<div className="profile-item mt-2">
<strong>Access Token (from server):</strong>
<pre
className="mt-1 p-2 bg-gray-800 rounded text-xs break-all"
style={{ fontFamily: "var(--font-geist-mono)" }}
>
{session?.accessToken || "Not available or not authenticated"}
</pre>
</div>
</div>

{/* Optional: Demonstrate client-side hooks */}
<PublicSSRClientInfo
initialIsAuthenticated={isAuthenticatedOnServer}
initialAccessToken={session?.accessToken}
/>

<Link href="/" className="mt-6 text-blue-500 hover:underline">
← Back to Home
</Link>
</div>
);
}
8 changes: 7 additions & 1 deletion demos/nextjs-ssr-demo/src/middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,13 @@ import { NextResponse } from "next/server";
import { handleNhostMiddleware } from "./app/lib/nhost/server";

// Define public routes that don't require authentication
const publicRoutes = ["/signin", "/signup", "/verify"];
const publicRoutes = [
"/signin",
"/signup",
"/verify",
"/public-csr",
"/public-ssr",
];

export async function middleware(request: NextRequest) {
// Create a response that we'll modify as needed
Expand Down
67 changes: 37 additions & 30 deletions docs/reference/javascript/nhost-js/main.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -125,53 +125,60 @@ console.log(JSON.stringify(funcResp.body, null, 2));
// }
```

## Classes
## Interfaces

### NhostClient

Main client class that provides unified access to all Nhost services.
This class serves as the central interface for interacting with Nhost's
authentication, storage, GraphQL, and serverless functions capabilities.

#### Constructors
#### Properties

##### Constructor
##### auth

```ts
new NhostClient(
auth: Client,
storage: Client,
graphql: Client,
functions: Client,
sessionStorage: SessionStorage): NhostClient;
auth: Client;
```

Create a new Nhost client. This constructor is reserved for advanced use cases.
For typical usage, use [createClient](#createclient) or [createServerClient](#createserverclient) instead.
Authentication client providing methods for user sign-in, sign-up, and session management.
Use this client to handle all authentication-related operations.

###### Parameters
##### functions

| Parameter | Type | Description |
| ---------------- | ---------------------------------------------- | ---------------------------------------------- |
| `auth` | [`Client`](auth#client) | Authentication client instance |
| `storage` | [`Client`](storage#client) | Storage client instance |
| `graphql` | [`Client`](graphql#client) | GraphQL client instance |
| `functions` | [`Client`](functions#client) | Functions client instance |
| `sessionStorage` | [`SessionStorage`](session#sessionstorage) | Storage implementation for session persistence |
```ts
functions: Client;
```

###### Returns
Functions client providing methods for invoking serverless functions.
Use this client to call your custom serverless functions deployed to Nhost.

[`NhostClient`](#nhostclient)
##### graphql

#### Properties
```ts
graphql: Client;
```

GraphQL client providing methods for executing GraphQL operations against your Hasura backend.
Use this client to query and mutate data in your database through GraphQL.

| Property | Type | Description |
| -------------------------------------------- | ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| <a id="auth"></a> `auth` | [`Client`](auth#client) | Authentication client providing methods for user sign-in, sign-up, and session management. Use this client to handle all authentication-related operations. |
| <a id="functions"></a> `functions` | [`Client`](functions#client) | Functions client providing methods for invoking serverless functions. Use this client to call your custom serverless functions deployed to Nhost. |
| <a id="graphql"></a> `graphql` | [`Client`](graphql#client) | GraphQL client providing methods for executing GraphQL operations against your Hasura backend. Use this client to query and mutate data in your database through GraphQL. |
| <a id="sessionstorage"></a> `sessionStorage` | [`SessionStorage`](session#sessionstorage) | Storage implementation used for persisting session information. This handles saving, retrieving, and managing authentication sessions across requests. |
| <a id="storage"></a> `storage` | [`Client`](storage#client) | Storage client providing methods for file operations (upload, download, delete). Use this client to manage files in your Nhost storage. |
##### sessionStorage

```ts
sessionStorage: SessionStorage;
```

Storage implementation used for persisting session information.
This handles saving, retrieving, and managing authentication sessions across requests.

##### storage

```ts
storage: Client;
```

Storage client providing methods for file operations (upload, download, delete).
Use this client to manage files in your Nhost storage.

#### Methods

Expand Down Expand Up @@ -260,7 +267,7 @@ const refreshedSession = await nhost.refreshSession(300);
const forcedRefresh = await nhost.refreshSession(0);
```

## Interfaces
---

### NhostClientOptions

Expand Down
Loading