Closed mw10013 closed 10 months ago
remix-server-runtime > sessions.ts
/**
* Creates a SessionStorage object using a SessionIdStorageStrategy.
*
* Note: This is a low-level API that should only be used if none of the
* existing session storage options meet your requirements.
*
* @see https://remix.run/utils/sessions#createsessionstorage
*/
export const createSessionStorageFactory =
(createCookie: CreateCookieFunction): CreateSessionStorageFunction =>
({ cookie: cookieArg, createData, readData, updateData, deleteData }) => {
let cookie = isCookie(cookieArg)
? cookieArg
: createCookie(cookieArg?.name || "__session", cookieArg);
warnOnceAboutSigningSessionCookie(cookie);
return {
async getSession(cookieHeader, options) {
let id = cookieHeader && (await cookie.parse(cookieHeader, options));
let data = id && (await readData(id));
return createSession(data || {}, id || "");
},
async commitSession(session, options) {
let { id, data } = session;
let expires =
options?.maxAge != null
? new Date(Date.now() + options.maxAge * 1000)
: options?.expires != null
? options.expires
: cookie.expires;
if (id) {
await updateData(id, data, expires);
} else {
id = await createData(data, expires);
}
return cookie.serialize(id, options);
},
async destroySession(session, options) {
await deleteData(session.id);
return cookie.serialize("", {
...options,
maxAge: undefined,
expires: new Date(0),
});
},
};
};
/**
* Returns true if an object is a Remix session.
*
* @see https://remix.run/utils/sessions#issession
*/
export const isSession: IsSessionFunction = (object): object is Session => {
return (
object != null &&
typeof object.id === "string" &&
typeof object.data !== "undefined" &&
typeof object.has === "function" &&
typeof object.get === "function" &&
typeof object.set === "function" &&
typeof object.flash === "function" &&
typeof object.unset === "function"
);
};
/**
* Creates a new Session object.
*
* Note: This function is typically not invoked directly by application code.
* Instead, use a `SessionStorage` object's `getSession` method.
*
* @see https://remix.run/utils/sessions#createsession
*/
export const createSession: CreateSessionFunction = <
Data = SessionData,
FlashData = Data
>(
initialData: Partial<Data> = {},
id = ""
): Session<Data, FlashData> => {
let map = new Map(Object.entries(initialData)) as Map<
keyof Data | FlashDataKey<keyof FlashData & string>,
any
>;
return {
get id() {
return id;
},
get data() {
return Object.fromEntries(map) as FlashSessionData<Data, FlashData>;
},
has(name) {
return (
map.has(name as keyof Data) ||
map.has(flash(name as keyof FlashData & string))
);
},
get(name) {
if (map.has(name as keyof Data)) return map.get(name as keyof Data);
let flashName = flash(name as keyof FlashData & string);
if (map.has(flashName)) {
let value = map.get(flashName);
map.delete(flashName);
return value;
}
return undefined;
},
set(name, value) {
map.set(name, value);
},
flash(name, value) {
map.set(flash(name), value);
},
unset(name) {
map.delete(name);
},
};
};