Node.js platform abstractions and utilities for Remix applications
—
Node.js-specific implementations of cookie and session utilities using cookie-signature for secure signing and various storage strategies.
Creates a cookie with Node.js-specific signing using the cookie-signature library.
/**
* Creates a cookie with Node.js-specific signing
* @param name - The name of the cookie
* @param cookieOptions - Configuration options for the cookie
* @returns Cookie instance
*/
function createCookie(name: string, cookieOptions?: CookieOptions): Cookie;Usage Examples:
import { createCookie } from "@remix-run/node";
// Basic cookie
const sessionCookie = createCookie("__session");
// Cookie with options
const secureCookie = createCookie("user-prefs", {
maxAge: 86400, // 24 hours
httpOnly: true,
secure: process.env.NODE_ENV === "production",
sameSite: "lax",
secrets: ["cookie-secret-key"]
});
// Use in a Remix loader
export async function loader({ request }: LoaderFunctionArgs) {
const cookieHeader = request.headers.get("Cookie");
const userPrefs = await secureCookie.parse(cookieHeader);
return json({ preferences: userPrefs });
}
// Use in a Remix action
export async function action({ request }: ActionFunctionArgs) {
const formData = await request.formData();
const theme = formData.get("theme");
return redirect("/", {
headers: {
"Set-Cookie": await secureCookie.serialize({ theme })
}
});
}Creates cookie-based session storage where session data is stored in the cookie itself.
/**
* Creates cookie-based session storage
* @param options - Configuration options for cookie session storage
* @returns SessionStorage instance that stores data in cookies
*/
function createCookieSessionStorage<Data = SessionData, FlashData = Data>(
options: CookieSessionStorageOptions
): SessionStorage<Data, FlashData>;Usage Examples:
import { createCookieSessionStorage } from "@remix-run/node";
// Basic cookie session storage
const sessionStorage = createCookieSessionStorage({
cookie: {
name: "__session",
secrets: ["session-secret"],
maxAge: 86400 // 24 hours
}
});
// Advanced configuration
const sessionStorage = createCookieSessionStorage({
cookie: {
name: "__session",
secrets: ["primary-secret", "fallback-secret"],
maxAge: 86400,
httpOnly: true,
secure: process.env.NODE_ENV === "production",
sameSite: "lax",
path: "/",
domain: process.env.NODE_ENV === "production" ? ".example.com" : undefined
}
});
// Use in authentication
export async function loader({ request }: LoaderFunctionArgs) {
const session = await sessionStorage.getSession(
request.headers.get("Cookie")
);
const userId = session.get("userId");
const user = userId ? await getUserById(userId) : null;
return json({ user });
}
export async function action({ request }: ActionFunctionArgs) {
const formData = await request.formData();
const email = String(formData.get("email"));
const password = String(formData.get("password"));
const user = await authenticateUser(email, password);
if (user) {
const session = await sessionStorage.getSession();
session.set("userId", user.id);
return redirect("/dashboard", {
headers: {
"Set-Cookie": await sessionStorage.commitSession(session)
}
});
}
return json({ error: "Invalid credentials" }, { status: 400 });
}Creates generic session storage with custom storage strategy.
/**
* Creates session storage with custom storage strategy
* @param options - Configuration options including storage strategy
* @returns SessionStorage instance with custom storage
*/
function createSessionStorage<Data = SessionData, FlashData = Data>(
options: SessionStorageOptions<Data, FlashData>
): SessionStorage<Data, FlashData>;Usage Examples:
import { createSessionStorage } from "@remix-run/node";
// Custom database session storage
const databaseSessionStorage = createSessionStorage({
cookie: {
name: "__session",
secrets: ["session-secret"],
maxAge: 86400
},
async createData(data, expires) {
const sessionId = generateId();
await db.sessions.create({
id: sessionId,
data: JSON.stringify(data),
expires
});
return sessionId;
},
async readData(id) {
const session = await db.sessions.findUnique({ where: { id } });
if (!session || (session.expires && session.expires < new Date())) {
return null;
}
return JSON.parse(session.data);
},
async updateData(id, data, expires) {
await db.sessions.update({
where: { id },
data: {
data: JSON.stringify(data),
expires
}
});
},
async deleteData(id) {
await db.sessions.delete({ where: { id } });
}
});Creates in-memory session storage for development and testing.
/**
* Creates in-memory session storage
* @param options - Optional configuration for memory session storage
* @returns SessionStorage instance that stores data in memory
*/
function createMemorySessionStorage<Data = SessionData, FlashData = Data>(
options?: MemorySessionStorageOptions
): SessionStorage<Data, FlashData>;Usage Examples:
import { createMemorySessionStorage } from "@remix-run/node";
// Basic memory session storage
const sessionStorage = createMemorySessionStorage();
// With custom cookie configuration
const sessionStorage = createMemorySessionStorage({
cookie: {
name: "__session",
maxAge: 3600, // 1 hour
httpOnly: true,
secure: false // OK for development
}
});
// Development authentication
export async function loader({ request }: LoaderFunctionArgs) {
const session = await sessionStorage.getSession(
request.headers.get("Cookie")
);
const user = session.get("user");
return json({ user });
}
export async function action({ request }: ActionFunctionArgs) {
const session = await sessionStorage.getSession(
request.headers.get("Cookie")
);
// Store user in memory session
session.set("user", { id: 1, name: "Test User" });
return redirect("/", {
headers: {
"Set-Cookie": await sessionStorage.commitSession(session)
}
});
}All session storage implementations provide the same interface:
interface SessionStorage<Data = SessionData, FlashData = Data> {
/**
* Parses a Cookie header and returns a Session or null if cookie is invalid
*/
getSession(cookieHeader?: string | null): Promise<Session<Data, FlashData>>;
/**
* Stores all data in the session and returns a Set-Cookie header
*/
commitSession(
session: Session<Data, FlashData>,
options?: CookieSerializeOptions
): Promise<string>;
/**
* Destroys the session and returns a Set-Cookie header that expires the cookie
*/
destroySession(
session: Session<Data, FlashData>,
options?: CookieSerializeOptions
): Promise<string>;
}
interface Session<Data = SessionData, FlashData = Data> {
/** Unique session identifier */
readonly id: string;
/** Session data */
readonly data: Partial<Data>;
/** Check if the session has a value for the given key */
has(key: keyof Data | keyof FlashData): boolean;
/** Get a value from the session */
get<Key extends keyof Data>(key: Key): Data[Key] | undefined;
/** Set a value in the session */
set<Key extends keyof Data>(key: Key, value: Data[Key]): void;
/** Flash a value that will be available only on the next request */
flash<Key extends keyof FlashData>(key: Key, value: FlashData[Key]): void;
/** Remove a value from the session */
unset(key: keyof Data | keyof FlashData): void;
}| Storage Type | Data Location | Capacity | Performance | Persistence |
|---|---|---|---|---|
| Cookie | Client browser | ~4KB | Fast | Browser-dependent |
| Memory | Server RAM | Unlimited | Fastest | Process lifetime |
| File | Server filesystem | Unlimited | Good | Persistent |
| Custom | User-defined | Varies | Varies | User-defined |
Install with Tessl CLI
npx tessl i tessl/npm-remix-run--node