Unfortunately, there is no "one size fits all" solution because each framework handle SSR differently (and even in a single framework there is more than one way of doing things).
But in general, the idea is to use a cookie based flow:
Create a new
XGenClientinstance for each server-side request"Load/Feed" your
xg.authStorewith data from the request cookiePerform your application server-side actions
Before returning the response to the client, update the cookie with the latest
xg.authStorestate
All BaseAuthStore instances have 2 helper methods that should make working with cookies a little bit easier:
// update the store with the parsed data from the cookie string
xg.authStore.loadFromCookie('xgen_token=...;xgen_user=...;xgen_session=...');
// exports the store data as cookie, with option to extend the default SameSite, Secure, HttpOnly, Path and Expires attributes
xg.authStore.exportToCookie({ httpOnly: false }); // Output: 'xgen_token=...;xgen_user=...;xgen_session=...'Below you can find an example of how to integrate with Express:
Express
One way to integrate with Express could be to create the XGen client in a [middleware](https://expressjs.com/en/guide/using-middleware.html) and pass it to the other routes using the res.locals.
Note: Your server will need to handle CORS
set the allowed origin and
credentials: trueon your serverMake sure to include
credentials: includewhen making the fetch callWhen calling
xg.authStore.exportToCookie()make sure you pass the option to switchsameSite: falsexg.authStore.exportToCookie({secure: true, sameSite: false, httpOnly: true, path: '/'})
// src/index.ts
import express from 'express';
import XGenClient, { type ClientParams } from '@xgenai/sdk-core';
// locals typescript
declare global {
namespace Express {
interface Locals {
xg: XGenClient;
}
}
}
const clientParams: ClientParams = {
key: 'client-key',
secret: 'client-secret',
clientId: 'client-id',
trackerId: 'tracker-id',
};
export const app = express();
const port = 3000;
// Middleware - creates a new client and loads the cookie info (user, session, token data)
app.use((req, res, next) => {
const xg = new XGenClient(clientParams);
if (xg) {
res.locals.xg = xg;
}
xg.authStore.loadFromCookie(req.headers.cookie || '');
next();
});
// Routes
app.get('/', (_, res) => {
res.send('Healthy!');
});
app.get('/products', async (_, res) => {
try {
const recommendations = await res.locals.xg.recommend.getResultsById({
elementId: '<element_id>',
});
res.setHeader('Set-Cookie', res.locals.xg.authStore.exportToCookie());
res.send(recommendations);
} catch (err) {
console.error(err);
res.send(err);
}
});
// Server
app.listen(port, () => {
console.logExample app listening on port ${port});
});Below you can find an example of how to integrate with SvelteKit SSR:
SvelteKit
One way to integrate with SvelteKit SSR could be to create the XGen client in a hook handle and pass it to the other server-side actions using the event.locals.
// src/hooks.server.js
import XGenClient from '@xgenai/sdk-core';
/** @type {import('@sveltejs/kit').Handle} */
export async function handle({ event, resolve }) {
event.locals.xg = new XGenClient({/*params*/});
// load the store data from the request cookie string
event.locals.xg.authStore.loadFromCookie(event.request.headers.get('cookie') || '');
const response = await resolve(event);
// send back the default 'xgen_token', 'xgen_user', 'xgen_session' cookies to the client with the latest store state
response.headers.append('set-cookie', event.locals.xg.authStore.exportToCookie());
return response;
}And then, in some of your server-side actions, you could directly access the previously created event.locals.xg instance:
// src/routes/recommendations/+server.js
/**
* Creates a `POST /recommendations` server-side endpoint
*
* @type {import('./$types').RequestHandler}
*/
export async function POST({ request, locals }) {
const { email, password } = await request.json();
const results = await xg.recommend.getResultsById({elementId: '<element_id>'})
return new Response(results);
}For proper locals.xg type detection, you can also add XGenClient in your your global types definition:
// src/app.d.ts
import XGenClient from '@xgenai/sdk-core';
declare global {
declare namespace App {
interface Locals {
xg: XGenClient
}
}
}