@analog-tools/session
Version:
Session management for AnalogJS server-side applications
2 lines (1 loc) • 5.66 kB
JavaScript
;Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const S=require("h3"),p=require("unstorage"),_=require("ioredis");let f=(e=21)=>crypto.getRandomValues(new Uint8Array(e)).reduce((t,s)=>(s&=63,s<36?t+=s.toString(36):s<62?t+=(s-26).toString(36).toUpperCase():s>62?t+="-":t+="_",t),"");async function h(e,t){if(typeof globalThis<"u"&&globalThis.crypto&&globalThis.crypto.subtle){const s=new TextEncoder,r=await globalThis.crypto.subtle.importKey("raw",s.encode(t),{name:"HMAC",hash:"SHA-256"},!1,["sign"]),c=await globalThis.crypto.subtle.sign("HMAC",r,s.encode(e)),l=C(c).replace(/=+$/,"");return`s:${e}.${l}`}throw new Error("Crypto API not available - ensure you are running in a compatible environment with Web Crypto API support")}async function x(e,t){if(!e.startsWith("s:"))return null;const[,s]=e.split("s:",2),r=s.lastIndexOf(".");if(r===-1)return null;const c=s.slice(0,r),l=s.slice(r+1);for(const u of t)try{const n=await h(c,u),[,a]=n.split("s:",2),o=a.slice(a.lastIndexOf(".")+1);if(k(l,o))return c}catch{continue}return null}function C(e){const t=new Uint8Array(e);let s="";for(let r=0;r<t.byteLength;r++)s+=String.fromCharCode(t[r]);return btoa(s)}function k(e,t){if(e.length!==t.length)return!1;let s=0;for(let r=0;r<e.length;r++)s|=e.charCodeAt(r)^t.charCodeAt(r);return s===0}const w="__session_data__",g="__session_id__";async function A(e,t){var c,l,u,n,a;const s=t.name||"connect.sid",r=Array.isArray(t.secret)?t.secret:[t.secret];e.context.__session_config__=t;try{const o=S.getCookie(e,s);let i=null;o&&(i=await x(o,r));let m;if(i){const d=await t.store.getItem(i);d?m=d:(i=f(),m=t.generate?t.generate():{})}else i=f(),m=t.generate?t.generate():{};e.context[w]=m,e.context[g]=i;try{const d=await h(i,r[0]);S.setCookie(e,s,d,{maxAge:t.maxAge||86400,httpOnly:((c=t.cookie)==null?void 0:c.httpOnly)??!0,secure:((l=t.cookie)==null?void 0:l.secure)??!1,sameSite:((u=t.cookie)==null?void 0:u.sameSite)??"lax",domain:(n=t.cookie)==null?void 0:n.domain,path:((a=t.cookie)==null?void 0:a.path)||"/"})}catch(d){throw y("COOKIE_ERROR","Failed to sign or set session cookie",{error:d})}try{await t.store.setItem(i,m)}catch(d){throw y("STORAGE_ERROR","Failed to save session data to store",{error:d})}}catch(o){throw y("CRYPTO_ERROR","An unexpected error occurred during session initialization",{error:o})}}function I(e){return e.context[w]||null}async function R(e,t){const s=I(e),r=e.context[g];if(!s||!r)throw y("INVALID_SESSION","No active session found");const c=t(s),l={...s,...c};e.context[w]=l;const u=e.context.__session_config__;u!=null&&u.store&&await u.store.setItem(r,l)}async function E(e){const t=e.context[g],s=e.context.__session_config__;if(t)try{s!=null&&s.store&&await s.store.removeItem(t),delete e.context[w],delete e.context[g];const r=(s==null?void 0:s.name)||"connect.sid";S.setCookie(e,r,"",{maxAge:0,httpOnly:!0,path:"/"})}catch(r){throw y("STORAGE_ERROR","Failed to destroy session",{error:r})}}async function O(e){var c,l,u,n,a;const t=I(e),s=e.context[g],r=e.context.__session_config__;if(!t||!s||!r)throw y("INVALID_SESSION","No active session to regenerate");try{const o=f();e.context[g]=o,await r.store.setItem(o,t),await r.store.removeItem(s);const i=Array.isArray(r.secret)?r.secret:[r.secret],m=await h(o,i[0]),d=r.name||"connect.sid";S.setCookie(e,d,m,{maxAge:r.maxAge||86400,httpOnly:((c=r.cookie)==null?void 0:c.httpOnly)??!0,secure:((l=r.cookie)==null?void 0:l.secure)??!1,sameSite:((u=r.cookie)==null?void 0:u.sameSite)??"lax",domain:(n=r.cookie)==null?void 0:n.domain,path:((a=r.cookie)==null?void 0:a.path)||"/"})}catch(o){throw y("STORAGE_ERROR","Failed to regenerate session",{error:o})}}function y(e,t,s){const r=new Error(t);return r.code=e,r.details=s,r}function T(e,t=":"){return e?e.replace(/[:/\\]/g,t).replace(/^[:/\\]|[:/\\]$/g,""):""}function b(...e){return e.map(t=>T(t)).filter(Boolean).join(":")}const N="memory",D=()=>{const e=new Map;return{name:N,getInstance:()=>e,hasItem(t){return e.has(t)},getItem(t){return e.get(t)??null},getItemRaw(t){return e.get(t)??null},setItem(t,s){e.set(t,s)},setItemRaw(t,s){e.set(t,s)},removeItem(t){e.delete(t)},getKeys(){return[...e.keys()]},clear(){e.clear()},dispose(){e.clear()}}},M="redis",K=e=>{let t;const s=()=>t||(e.cluster?t=new _.Cluster(e.cluster,e.clusterOptions):e.url?t=new _(e.url,e):t=new _(e),t),r=(e.base||"").replace(/:$/,""),c=(...n)=>b(r,...n),l=n=>r?n.replace(`${r}:`,""):n;if(e.preConnect)try{s()}catch(n){console.error(n)}const u=async n=>{const a=s(),o=[];let i="0";do{const[m,d]=e.scanCount?await a.scan(i,"MATCH",n,"COUNT",e.scanCount):await a.scan(i,"MATCH",n);i=m,o.push(...d)}while(i!=="0");return o};return{name:M,options:e,getInstance:s,async hasItem(n){return!!await s().exists(c(n))},async getItem(n){return await s().get(c(n))??null},async getItems(n){const a=n.map(i=>c(i.key)),o=await s().mget(...a);return a.map((i,m)=>({key:l(i),value:o[m]??null}))},async setItem(n,a,o){const i=(o==null?void 0:o.ttl)??e.ttl;i?await s().set(c(n),a,"EX",i):await s().set(c(n),a)},async removeItem(n){await s().unlink(c(n))},async getKeys(n){return(await u(c(n,"*"))).map(o=>l(o))},async clear(n){const a=await u(c(n,"*"));a.length!==0&&await s().unlink(a)},dispose(){return s().disconnect()}}};function $(){return p.createStorage({driver:D()})}function H(e){return p.createStorage({driver:K({url:e.url,host:e.host,port:e.port,username:e.username,password:e.password,db:e.db,ttl:e.ttl})})}exports.createMemoryStore=$;exports.createRedisStore=H;exports.destroySession=E;exports.getSession=I;exports.regenerateSession=O;exports.signCookie=h;exports.unsignCookie=x;exports.updateSession=R;exports.useSession=A;