| 1 | |
| 2 | |
| 3 | |
| 4 | |
| 5 | |
| 6 | |
| 7 | |
| 8 | |
| 9 | |
| 10 |
|
| 11 | import { warnOnce } from "./warnings.js";
|
| 12 | import { createCookie, isCookie } from "./cookies.js";
|
| 13 |
|
| 14 | function flash(name) {
|
| 15 | return `__flash_${name}__`;
|
| 16 | }
|
| 17 | |
| 18 | |
| 19 | |
| 20 | |
| 21 | |
| 22 |
|
| 23 | const createSession = (initialData = {}, id = "") => {
|
| 24 | let map = new Map(Object.entries(initialData));
|
| 25 | return {
|
| 26 | get id() {
|
| 27 | return id;
|
| 28 | },
|
| 29 | get data() {
|
| 30 | return Object.fromEntries(map);
|
| 31 | },
|
| 32 | has(name) {
|
| 33 | return map.has(name) || map.has(flash(name));
|
| 34 | },
|
| 35 | get(name) {
|
| 36 | if (map.has(name)) return map.get(name);
|
| 37 | let flashName = flash(name);
|
| 38 | if (map.has(flashName)) {
|
| 39 | let value = map.get(flashName);
|
| 40 | map.delete(flashName);
|
| 41 | return value;
|
| 42 | }
|
| 43 | },
|
| 44 | set(name, value) {
|
| 45 | map.set(name, value);
|
| 46 | },
|
| 47 | flash(name, value) {
|
| 48 | map.set(flash(name), value);
|
| 49 | },
|
| 50 | unset(name) {
|
| 51 | map.delete(name);
|
| 52 | }
|
| 53 | };
|
| 54 | };
|
| 55 | |
| 56 | |
| 57 | |
| 58 | |
| 59 |
|
| 60 | const isSession = (object) => {
|
| 61 | 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";
|
| 62 | };
|
| 63 | |
| 64 | |
| 65 | |
| 66 | |
| 67 | |
| 68 |
|
| 69 | function createSessionStorage({ cookie: cookieArg, createData, readData, updateData, deleteData }) {
|
| 70 | let cookie = isCookie(cookieArg) ? cookieArg : createCookie(cookieArg?.name || "__session", cookieArg);
|
| 71 | warnOnceAboutSigningSessionCookie(cookie);
|
| 72 | return {
|
| 73 | async getSession(cookieHeader, options) {
|
| 74 | let id = cookieHeader && await cookie.parse(cookieHeader, options);
|
| 75 | return createSession(id && await readData(id) || {}, id || "");
|
| 76 | },
|
| 77 | async commitSession(session, options) {
|
| 78 | let { id, data } = session;
|
| 79 | let expires = options?.maxAge != null ? new Date(Date.now() + options.maxAge * 1e3) : options?.expires != null ? options.expires : cookie.expires;
|
| 80 | if (id) await updateData(id, data, expires);
|
| 81 | else id = await createData(data, expires);
|
| 82 | return cookie.serialize(id, options);
|
| 83 | },
|
| 84 | async destroySession(session, options) {
|
| 85 | await deleteData(session.id);
|
| 86 | return cookie.serialize("", {
|
| 87 | ...options,
|
| 88 | maxAge: void 0,
|
| 89 | expires: new Date(0)
|
| 90 | });
|
| 91 | }
|
| 92 | };
|
| 93 | }
|
| 94 | function warnOnceAboutSigningSessionCookie(cookie) {
|
| 95 | warnOnce(cookie.isSigned, `The "${cookie.name}" cookie is not signed, but session cookies should be signed to prevent tampering on the client before they are sent back to the server. See https://reactrouter.com/explanation/sessions-and-cookies#signing-cookies for more information.`);
|
| 96 | }
|
| 97 |
|
| 98 | export { createSession, createSessionStorage, isSession, warnOnceAboutSigningSessionCookie };
|