aui-auth 0.0.3 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- import { m as SignInInput, p as RevalidateInput } from "./types-C79_29ZY.js";
1
+ import { m as SignInInput, p as RevalidateInput } from "./types-BcXM3ZEI.js";
2
2
  //#region src/accounts/index.d.ts
3
3
  type AccountsOrganization = {
4
4
  id: string;
package/dist/accounts.js CHANGED
@@ -1 +1 @@
1
- import{a as e,m as t}from"./cache-DuVjR2sZ.js";async function n(n,r){let i=await(n.fetch??globalThis.fetch.bind(globalThis))(e(n.issuer,`/api/oidc/organizations`),{headers:{Authorization:`Bearer ${r}`},cache:`no-store`});if(!i.ok)throw new t(`Failed to load organizations: ${i.status}`,i.status);return await i.json()}function r(e,t){if(t){let n=e.find(e=>e.slug===t);if(n)return n}return e[0]??null}function i(e){let[,t]=new URL(e,`http://localhost`).pathname.split(`/`);return t&&t!==`org`?t:null}function a(e){let a=e.preferredSlug??i;async function o(t){return{activeOrganization:r(await n(e,t.accessToken),a(t.redirectPath))}}async function s(i){let a;try{a=await n(e,i.accessToken)}catch(e){if(e instanceof t&&e.status>=400&&e.status<500)return null;throw e}let o=i.session.data.activeOrganization;if(!o)return{activeOrganization:r(a)};let s=a.find(e=>e.id===o.id)??null;return s?{activeOrganization:s}:null}return{onSignIn:o,onRevalidate:s}}export{n as fetchOrganizations,a as organizationHooks,i as preferredOrganizationSlug,r as selectOrganization};
1
+ import{a as e,m as t}from"./cache-BWpH93Oi.js";async function n(n,r){let i=await(n.fetch??globalThis.fetch.bind(globalThis))(e(n.issuer,`/api/oidc/organizations`),{headers:{Authorization:`Bearer ${r}`},cache:`no-store`});if(!i.ok)throw new t(`Failed to load organizations: ${i.status}`,i.status);return await i.json()}function r(e,t){if(t){let n=e.find(e=>e.slug===t);if(n)return n}return e[0]??null}function i(e){let[,t]=new URL(e,`http://localhost`).pathname.split(`/`);return t&&t!==`org`?t:null}function a(e){let a=e.preferredSlug??i;async function o(t){return{activeOrganization:r(await n(e,t.accessToken),a(t.redirectPath))}}async function s(i){let a;try{a=await n(e,i.accessToken)}catch(e){if(e instanceof t&&e.status>=400&&e.status<500)return null;throw e}let o=i.session.data.activeOrganization;if(!o)return{activeOrganization:r(a)};let s=a.find(e=>e.id===o.id)??null;return s?{activeOrganization:s}:null}return{onSignIn:o,onRevalidate:s}}export{n as fetchOrganizations,a as organizationHooks,i as preferredOrganizationSlug,r as selectOrganization};
@@ -0,0 +1 @@
1
+ import{t as e}from"./codec-BcgaGRoP.js";function t(e){if(!e)return;let t=e.split(`,`);return t[t.length-1].trim()||void 0}function n(e){let n=new URL(e.url);return`${t(e.headers.get(`x-forwarded-proto`))||n.protocol.replace(`:`,``)}://${t(e.headers.get(`x-forwarded-host`))||e.headers.get(`host`)||n.host}`}function r(e){return new URL(e).protocol===`https:`}function i(e,t){return t?`__Secure-${e}`:e}function a(e){let t=new Map;if(!e)return t;for(let n of e.split(`;`)){let e=n.indexOf(`=`);if(e===-1)continue;let r=n.slice(0,e).trim();!r||t.has(r)||t.set(r,n.slice(e+1).trim())}return t}function o(e,t){let n=a(e.headers.get(`cookie`));return n.get(i(t,!0))||n.get(i(t,!1))||null}function s(e,t,n,r){let i=[`${e}=${t}`,`Path=/`,`HttpOnly`,`SameSite=Lax`,`Max-Age=${r}`];return n&&i.push(`Secure`),i.join(`; `)}function c(e,t,n,a,o){let c=r(a);e.append(`set-cookie`,s(i(t,c),n,c,Math.floor(o/1e3)))}function l(e,t){let n=r(t);return[n,!n].map(t=>s(i(e,t),``,t,0))}function u(e,t,n){for(let r of l(t,n))e.append(`set-cookie`,r)}function d(e,t=307){return new Response(null,{status:t,headers:{location:e.toString()}})}function f(e,t){return`${e}_flow_${t}`}function p(e){return btoa(JSON.stringify(e)).replace(/\+/g,`-`).replace(/\//g,`_`).replace(/=+$/g,``)}function m(e){if(!e)return null;try{let t=e.replace(/-/g,`+`).replace(/_/g,`/`),n=JSON.parse(atob(t));return typeof n.verifier==`string`?{verifier:n.verifier,redirectPath:typeof n.redirectPath==`string`?n.redirectPath:`/`,silent:n.silent===!0}:null}catch{return null}}function h(e,t){if(!e)return`/`;let n;try{n=new URL(e,t)}catch{return`/`}return n.origin===t?`${n.pathname}${n.search}${n.hash}`:`/`}const g={login:`/api/auth/login`,callback:`/api/auth/callback`,logout:`/api/auth/logout`,logoutComplete:`/api/auth/logout-complete`,error:`/auth/error`},_={absoluteMaxAgeMs:2592e6,idleMaxAgeMs:6048e5,revalidateIntervalMs:12e4,refreshBeforeExpiryMs:3e5,flowMaxAgeMs:6e5,refreshLeaseMs:2e4,leaseWaitMs:5e3},v=Object.freeze({});function y(e){return{...e,scope:e.scope??`openid profile email offline_access`,onSignIn:e.onSignIn??(async()=>v),onRevalidate:e.onRevalidate??(async()=>v),paths:{...g,...e.paths},lifetimes:{..._,...e.lifetimes},fetch:e.fetch??globalThis.fetch.bind(globalThis),now:e.now??Date.now,cache:e.cache?{codec:F(e.cache.secret),maxAgeMs:e.cache.maxAgeMs??6e4}:null,audience:e.audience===!1?null:e.audience??new URL(`/api/auth`,e.issuer).toString()}}var b=class extends Error{status;constructor(e,t){super(e),this.name=`AccountsRequestError`,this.status=t}},x=class extends b{code;description;constructor(e,t,n){super(`Token request failed: ${e} ${t} ${n}`,e),this.name=`OAuthTokenError`,this.code=t,this.description=n}};function S(e){let t=``;for(let n of e)t+=String.fromCharCode(n);return btoa(t).replace(/\+/g,`-`).replace(/\//g,`_`).replace(/=+$/g,``)}function C(e){return S(crypto.getRandomValues(new Uint8Array(e)))}async function w(e){let t=await crypto.subtle.digest(`SHA-256`,new TextEncoder().encode(e));return S(new Uint8Array(t))}function T(e,t){return new URL(t,e).toString()}async function E(e,t){let n=C(24),r=C(32),i=new URL(T(e.issuer,`/api/auth/oauth2/authorize`));return i.searchParams.set(`client_id`,e.clientId),i.searchParams.set(`redirect_uri`,new URL(e.paths.callback,t.origin).toString()),i.searchParams.set(`response_type`,`code`),i.searchParams.set(`scope`,e.scope),i.searchParams.set(`state`,n),i.searchParams.set(`code_challenge`,await w(r)),i.searchParams.set(`code_challenge_method`,`S256`),t.silent&&i.searchParams.set(`prompt`,`none`),{url:i.toString(),state:n,verifier:r}}function D(e,t){let n=new URL(T(e.issuer,`/api/auth/oauth2/end-session`));return n.searchParams.set(`id_token_hint`,t.idToken),n.searchParams.set(`client_id`,e.clientId),n.searchParams.set(`post_logout_redirect_uri`,new URL(e.paths.logoutComplete,t.origin).toString()),n.toString()}async function O(e,t,n,r=!0){let i=new URLSearchParams({client_id:e.clientId,...t});e.clientSecret&&i.set(`client_secret`,e.clientSecret),e.audience&&r&&i.set(`resource`,e.audience);let a=n===void 0?void 0:n-Date.now();if(a!==void 0&&a<=0)throw new b(`Token request deadline passed`,0);let o=await e.fetch(T(e.issuer,`/api/auth/oauth2/token`),{method:`POST`,headers:{"Content-Type":`application/x-www-form-urlencoded`},body:i,cache:`no-store`,...a?{signal:AbortSignal.timeout(a)}:{}});if(!o.ok){let i=await o.text().catch(()=>``),a=`unknown_error`,s=i;try{let e=JSON.parse(i);a=e.error??a,s=e.error_description??s}catch{}if(r&&e.audience&&a===`invalid_request`&&/resource/i.test(s))return O(e,t,n,!1);throw new x(o.status,a,s)}return await o.json()}function k(e,t){return O(e,{grant_type:`authorization_code`,code:t.code,code_verifier:t.verifier,redirect_uri:t.redirectUri})}function A(e,t,n){return O(e,{grant_type:`refresh_token`,refresh_token:t},n===void 0?void 0:Date.now()+n)}async function j(e,t){let n=await(e.fetch??globalThis.fetch.bind(globalThis))(T(e.issuer,`/api/auth/oauth2/userinfo`),{headers:{Authorization:`Bearer ${t}`},cache:`no-store`});if(!n.ok)throw new b(`Failed to load user info: ${n.status}`,n.status);let r=await n.json();return{id:r.sub,email:r.email??``,name:r.name??r.email??r.sub,image:r.picture??null}}function M(e,t,n){return{accessToken:e.access_token,refreshToken:e.refresh_token??t?.refreshToken??null,idToken:e.id_token??t?.idToken??null,accessTokenExpiresAt:typeof e.expires_at==`number`?e.expires_at*1e3:n+(e.expires_in??3600)*1e3}}function N(e){return`${e}_cache`}function P(e){let t=``;for(let n of e)t+=n.toString(16).padStart(2,`0`);return t}function F(t){let n=null;return()=>n??=crypto.subtle.digest(`SHA-256`,new TextEncoder().encode(t)).then(t=>e(P(new Uint8Array(t))))}function I(e,t,n){if(!e.cache)return 0;let{lifetimes:r}=e;return Math.min(e.cache.maxAgeMs,t.lastValidatedAt+r.revalidateIntervalMs-n,t.tokens.accessTokenExpiresAt-r.refreshBeforeExpiryMs-n,t.createdAt+r.absoluteMaxAgeMs-n,t.lastValidatedAt+r.idleMaxAgeMs-n)}async function L(e,t,n){if(!e.cache)return null;let r=I(e,t,n);if(r<1e3)return null;let i={v:1,id:t.id,u:t.user,d:t.data,at:t.tokens.accessToken,ate:t.tokens.accessTokenExpiresAt,ca:t.createdAt,lv:t.lastValidatedAt,exp:n+r};return{value:await(await e.cache.codec()).encrypt(JSON.stringify(i)),maxAgeMs:r}}async function R(e,t,n,r){if(!e.cache||!t||!n)return null;let i;try{let n=await e.cache.codec();i=JSON.parse(await n.decrypt(t))}catch{return null}return i.v!==1||typeof i.exp!=`number`||i.exp<=r||i.id!==await w(n)?null:{id:i.id,user:i.u,tokens:{accessToken:i.at,refreshToken:null,idToken:null,accessTokenExpiresAt:i.ate},data:i.d,createdAt:i.ca,lastValidatedAt:i.lv,refreshLeaseUntil:null}}async function z(e,t,n,a){let o=await L(e,t,a);if(!o)return null;let c=r(n);return s(i(N(e.cookieName),c),o.value,c,Math.floor(o.maxAgeMs/1e3))}function B(e,t){return e.cache?l(N(e.cookieName),t):[]}export{o as C,c as D,h as E,f as S,n as T,u as _,T as a,m as b,k as c,A as d,w as f,y as g,x as h,R as i,j as l,b as m,N as n,E as o,M as p,z as r,D as s,B as t,C as u,l as v,d as w,p as x,i as y};
@@ -1,2 +1,2 @@
1
- import { c as AccountsSessionStore, g as createAesGcmCodec, h as SessionCodec, l as AccountsTokens, o as AccountsSession, s as AccountsSessionPatch, u as AccountsUser } from "../types-C79_29ZY.js";
1
+ import { c as AccountsSessionStore, g as createAesGcmCodec, h as SessionCodec, l as AccountsTokens, o as AccountsSession, s as AccountsSessionPatch, u as AccountsUser } from "../types-BcXM3ZEI.js";
2
2
  export { type AccountsSession, type AccountsSessionPatch, type AccountsSessionStore, type AccountsTokens, type AccountsUser, type SessionCodec, createAesGcmCodec };
@@ -1,4 +1,4 @@
1
- import { c as AccountsSessionStore, h as SessionCodec } from "../types-C79_29ZY.js";
1
+ import { c as AccountsSessionStore, h as SessionCodec } from "../types-BcXM3ZEI.js";
2
2
  //#region src/database/pg.d.ts
3
3
  type PgQuery = (text: string, values?: unknown[]) => Promise<{
4
4
  rows: Record<string, unknown>[];
@@ -11,4 +11,4 @@ const e=`CREATE TABLE "accounts_sessions" (
11
11
  "last_validated_at" timestamp with time zone NOT NULL,
12
12
  "refresh_lease_until" timestamp with time zone
13
13
  );
14
- CREATE INDEX "accounts_sessions_user_id_idx" ON "accounts_sessions" ("user_id");`,t={encrypt:async e=>e,decrypt:async e=>e};function n(e){if(e instanceof Date)return e.getTime();if(typeof e==`string`)return new Date(e).getTime();if(typeof e==`number`)return e;throw Error(`Unexpected timestamp value in accounts session row`)}function r(e){return new Date(e)}function i(e){let i=e.table??`accounts_sessions`;if(!/^[a-z_][a-z0-9_]*$/.test(i))throw Error(`Invalid accounts session table name: ${i}`);let a=`"${i}"`,o=e.codec??t;async function s(e){return{accessToken:await o.encrypt(e.accessToken),refreshToken:e.refreshToken?await o.encrypt(e.refreshToken):null,idToken:e.idToken?await o.encrypt(e.idToken):null}}async function c(e){return{id:e.id,user:e.user,tokens:{accessToken:await o.decrypt(e.access_token),refreshToken:e.refresh_token?await o.decrypt(e.refresh_token):null,idToken:e.id_token?await o.decrypt(e.id_token):null,accessTokenExpiresAt:n(e.access_token_expires_at)},data:e.data,createdAt:n(e.created_at),lastValidatedAt:n(e.last_validated_at),refreshLeaseUntil:e.refresh_lease_until===null||e.refresh_lease_until===void 0?null:n(e.refresh_lease_until)}}return{async create(t){let n=await s(t.tokens);await e.query(`INSERT INTO ${a} ("id", "user_id", "user", "access_token", "refresh_token", "id_token", "access_token_expires_at", "data", "created_at", "last_validated_at", "refresh_lease_until") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, NULL)`,[t.id,t.user.id,t.user,n.accessToken,n.refreshToken,n.idToken,r(t.tokens.accessTokenExpiresAt),t.data,r(t.createdAt),r(t.lastValidatedAt)])},async read(t){let{rows:n}=await e.query(`SELECT * FROM ${a} WHERE "id" = $1`,[t]);return n[0]?c(n[0]):null},async update(t,n,i){let o=[],l=[t],u=(e,t)=>{l.push(t),o.push(`"${e}" = $${l.length}`)};if(n.user!==void 0&&(u(`user_id`,n.user.id),u(`user`,n.user)),n.tokens!==void 0){let e=await s(n.tokens);u(`access_token`,e.accessToken),u(`refresh_token`,e.refreshToken),u(`id_token`,e.idToken),u(`access_token_expires_at`,r(n.tokens.accessTokenExpiresAt))}if(n.data!==void 0&&u(`data`,n.data),n.lastValidatedAt!==void 0&&u(`last_validated_at`,r(n.lastValidatedAt)),n.refreshLeaseUntil!==void 0&&u(`refresh_lease_until`,n.refreshLeaseUntil===null?null:r(n.refreshLeaseUntil)),o.length===0)return this.read(t);let d=`"id" = $1`;i!==void 0&&(l.push(r(i)),d+=` AND "refresh_lease_until" = $${l.length}`);let{rows:f}=await e.query(`UPDATE ${a} SET ${o.join(`, `)} WHERE ${d} RETURNING *`,l);return f[0]?c(f[0]):null},async claimRefreshLease(t,n,i){let{rows:o}=await e.query(`UPDATE ${a} SET "refresh_lease_until" = $2 WHERE "id" = $1 AND ("refresh_lease_until" IS NULL OR "refresh_lease_until" <= $3) RETURNING *`,[t,r(n),r(i)]);return o[0]?c(o[0]):null},async delete(t,n){if(n===void 0){await e.query(`DELETE FROM ${a} WHERE "id" = $1`,[t]);return}await e.query(`DELETE FROM ${a} WHERE "id" = $1 AND "refresh_lease_until" = $2`,[t,r(n)])}}}export{e as PG_SESSION_TABLE_SQL,i as createPgSessionStore};
14
+ CREATE INDEX "accounts_sessions_user_id_idx" ON "accounts_sessions" ("user_id");`,t={encrypt:async e=>e,decrypt:async e=>e};function n(e){if(e instanceof Date)return e.getTime();if(typeof e==`string`)return new Date(e).getTime();if(typeof e==`number`)return e;throw Error(`Unexpected timestamp value in accounts session row`)}function r(e){return new Date(e)}function i(e){let i=e.table??`accounts_sessions`;if(!/^[a-z_][a-z0-9_]*$/.test(i))throw Error(`Invalid accounts session table name: ${i}`);let a=`"${i}"`,o=e.codec??t;async function s(e){return{accessToken:await o.encrypt(e.accessToken),refreshToken:e.refreshToken?await o.encrypt(e.refreshToken):null,idToken:e.idToken?await o.encrypt(e.idToken):null}}async function c(e){return{id:e.id,user:e.user,tokens:{accessToken:await o.decrypt(e.access_token),refreshToken:e.refresh_token?await o.decrypt(e.refresh_token):null,idToken:e.id_token?await o.decrypt(e.id_token):null,accessTokenExpiresAt:n(e.access_token_expires_at)},data:e.data,createdAt:n(e.created_at),lastValidatedAt:n(e.last_validated_at),refreshLeaseUntil:e.refresh_lease_until===null||e.refresh_lease_until===void 0?null:n(e.refresh_lease_until)}}return{async create(t){let n=await s(t.tokens);await e.query(`INSERT INTO ${a} ("id", "user_id", "user", "access_token", "refresh_token", "id_token", "access_token_expires_at", "data", "created_at", "last_validated_at", "refresh_lease_until") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, NULL)`,[t.id,t.user.id,t.user,n.accessToken,n.refreshToken,n.idToken,r(t.tokens.accessTokenExpiresAt),t.data,r(t.createdAt),r(t.lastValidatedAt)])},async read(t){let{rows:n}=await e.query(`SELECT * FROM ${a} WHERE "id" = $1`,[t]);return n[0]?c(n[0]):null},async update(t,n,i){let o=[],l=[t],u=(e,t)=>{l.push(t),o.push(`"${e}" = $${l.length}`)};if(n.user!==void 0&&(u(`user_id`,n.user.id),u(`user`,n.user)),n.tokens!==void 0){let e=await s(n.tokens);u(`access_token`,e.accessToken),u(`refresh_token`,e.refreshToken),u(`id_token`,e.idToken),u(`access_token_expires_at`,r(n.tokens.accessTokenExpiresAt))}if(n.data!==void 0&&u(`data`,n.data),n.lastValidatedAt!==void 0&&u(`last_validated_at`,r(n.lastValidatedAt)),n.refreshLeaseUntil!==void 0&&u(`refresh_lease_until`,n.refreshLeaseUntil===null?null:r(n.refreshLeaseUntil)),o.length===0)return this.read(t);let d=`"id" = $1`;i!==void 0&&(l.push(r(i)),d+=` AND "refresh_lease_until" = $${l.length}`);let{rows:f}=await e.query(`UPDATE ${a} SET ${o.join(`, `)} WHERE ${d} RETURNING *`,l);return f[0]?c(f[0]):null},async claimRefreshLease(t,n,i){let{rows:o}=await e.query(`UPDATE ${a} SET "refresh_lease_until" = $2 WHERE "id" = $1 AND ("refresh_lease_until" IS NULL OR "refresh_lease_until" <= $3) RETURNING *`,[t,r(n),r(i)]);return o[0]?c(o[0]):null},async delete(t,n){if(n===void 0){let{rows:n}=await e.query(`DELETE FROM ${a} WHERE "id" = $1 RETURNING "id"`,[t]);return n.length>0}let{rows:i}=await e.query(`DELETE FROM ${a} WHERE "id" = $1 AND "refresh_lease_until" = $2 RETURNING "id"`,[t,r(n)]);return i.length>0}}}export{e as PG_SESSION_TABLE_SQL,i as createPgSessionStore};
@@ -0,0 +1,34 @@
1
+ import { c as AccountsSessionStore, h as SessionCodec } from "../types-BcXM3ZEI.js";
2
+ //#region src/database/redis.d.ts
3
+ /**
4
+ * The slice of a Redis client this store uses, so the package takes no Redis
5
+ * dependency of its own. The shape is `@upstash/redis`, which satisfies it
6
+ * directly. A client whose `eval` takes a key count and a flat argument list,
7
+ * ioredis for one, needs an adapter:
8
+ *
9
+ * ```ts
10
+ * const redis = {
11
+ * hgetall: (key) => client.hgetall(key),
12
+ * eval: (script, keys, args) =>
13
+ * client.eval(script, keys.length, ...keys, ...args),
14
+ * };
15
+ * ```
16
+ */
17
+ type RedisSessionClient = {
18
+ hgetall(key: string): Promise<Record<string, unknown> | null>;
19
+ eval(script: string, keys: string[], args: string[]): Promise<unknown>;
20
+ };
21
+ type RedisSessionStoreOptions = {
22
+ redis: RedisSessionClient;
23
+ codec?: SessionCodec;
24
+ /** Key prefix. One prefix per app, the way one table is one app. */
25
+ prefix?: string;
26
+ /**
27
+ * Key expiry, garbage collection only: it is renewed on every write and
28
+ * sessions carry their own limits, so it only has to exceed `idleMaxAgeMs`.
29
+ */
30
+ ttlMs?: number;
31
+ };
32
+ declare function createRedisSessionStore<Data>(options: RedisSessionStoreOptions): AccountsSessionStore<Data>;
33
+ //#endregion
34
+ export { RedisSessionClient, RedisSessionStoreOptions, createRedisSessionStore };
@@ -0,0 +1,43 @@
1
+ const e=`refreshLeaseUntil`,t=`
2
+ local key, checkLease, expectedLease, ttl = KEYS[1], ARGV[1], ARGV[2], ARGV[3]
3
+ if redis.call('EXISTS', key) == 0 then return 0 end
4
+ if checkLease == '1' then
5
+ local current = redis.call('HGET', key, '${e}')
6
+ if (current or '') ~= expectedLease then return 0 end
7
+ end
8
+ for index = 4, #ARGV, 2 do
9
+ if ARGV[index + 1] == '' then
10
+ redis.call('HDEL', key, ARGV[index])
11
+ else
12
+ redis.call('HSET', key, ARGV[index], ARGV[index + 1])
13
+ end
14
+ end
15
+ redis.call('PEXPIRE', key, ttl)
16
+ return 1
17
+ `,n=`
18
+ local key, leaseUntil, now, ttl = KEYS[1], ARGV[1], ARGV[2], ARGV[3]
19
+ if redis.call('EXISTS', key) == 0 then return nil end
20
+ local current = redis.call('HGET', key, '${e}')
21
+ if current and current ~= '' and tonumber(current) > tonumber(now) then
22
+ return nil
23
+ end
24
+ redis.call('HSET', key, '${e}', leaseUntil)
25
+ redis.call('PEXPIRE', key, ttl)
26
+ return redis.call('HGETALL', key)
27
+ `,r=`
28
+ local key, checkLease, expectedLease = KEYS[1], ARGV[1], ARGV[2]
29
+ if redis.call('EXISTS', key) == 0 then return 0 end
30
+ if checkLease == '1' then
31
+ local current = redis.call('HGET', key, '${e}')
32
+ if (current or '') ~= expectedLease then return 0 end
33
+ end
34
+ redis.call('DEL', key)
35
+ return 1
36
+ `,i={encrypt:async e=>e,decrypt:async e=>e};function a(e){return e==null||e===``?null:typeof e==`string`?e:JSON.stringify(e)}function o(e){let t=a(e),n=t===null?NaN:Number(t);if(!Number.isFinite(n))throw Error(`Unexpected timestamp in accounts session hash`);return n}function s(e){if(typeof e!=`string`)return e;try{return JSON.parse(e)}catch{return e}}function c(e){if(!e)return null;if(Array.isArray(e)){if(e.length===0)return null;let t={};for(let n=0;n<e.length;n+=2)t[String(e[n])]=e[n+1];return t}let t=e;return Object.keys(t).length>0?t:null}function l(l){let{redis:u}=l,d=l.codec??i,f=l.prefix??`accounts_sessions:`,p=l.ttlMs??26784e5,m=e=>`${f}${e}`;async function h(t){let n={};if(t.user&&(n.user=JSON.stringify(t.user)),t.data!==void 0&&(n.data=JSON.stringify(t.data)),t.lastValidatedAt!==void 0&&(n.lastValidatedAt=String(t.lastValidatedAt)),t.refreshLeaseUntil!==void 0&&(n[e]=t.refreshLeaseUntil===null?``:String(t.refreshLeaseUntil)),t.tokens){let{accessToken:e,refreshToken:r,idToken:i,accessTokenExpiresAt:a}=t.tokens;n.accessToken=await d.encrypt(e),n.refreshToken=r?await d.encrypt(r):``,n.idToken=i?await d.encrypt(i):``,n.accessTokenExpiresAt=String(a)}return n}async function g(t,n){let r=a(n.refreshToken),i=a(n.idToken),c=a(n[e]);return{id:t,user:s(n.user),tokens:{accessToken:await d.decrypt(a(n.accessToken)??``),refreshToken:r?await d.decrypt(r):null,idToken:i?await d.decrypt(i):null,accessTokenExpiresAt:o(n.accessTokenExpiresAt)},data:s(n.data),createdAt:o(n.createdAt),lastValidatedAt:o(n.lastValidatedAt),refreshLeaseUntil:c===null?null:Number(c)}}async function _(e){let t=c(await u.hgetall(m(e)));return t?g(e,t):null}return{async create(e){let t=await h(e);t.createdAt=String(e.createdAt);let n=Object.entries(t).filter(([,e])=>e!==``);await u.eval(`
37
+ local key, ttl = KEYS[1], ARGV[1]
38
+ for index = 2, #ARGV, 2 do
39
+ redis.call('HSET', key, ARGV[index], ARGV[index + 1])
40
+ end
41
+ redis.call('PEXPIRE', key, ttl)
42
+ return 1
43
+ `,[m(e.id)],[String(p),...n.flat()])},read:_,async update(e,n,r){let i=await h(n),a=await u.eval(t,[m(e)],[r===void 0?`0`:`1`,r===void 0?``:String(r),String(p),...Object.entries(i).flat()]);return Number(a)===1?_(e):null},async claimRefreshLease(e,t,r){let i=c(await u.eval(n,[m(e)],[String(t),String(r),String(p)]));return i?g(e,i):null},async delete(e,t){let n=await u.eval(r,[m(e)],[t===void 0?`0`:`1`,t===void 0?``:String(t)]);return Number(n)===1}}}export{l as createRedisSessionStore};
@@ -1,4 +1,4 @@
1
- import { c as AccountsSessionStore, f as ResolvedAccountsAuthConfig, l as AccountsTokens, o as AccountsSession, t as AccountsAuthConfig, u as AccountsUser } from "./types-C79_29ZY.js";
1
+ import { c as AccountsSessionStore, f as ResolvedAccountsAuthConfig, l as AccountsTokens, o as AccountsSession, t as AccountsAuthConfig, u as AccountsUser } from "./types-BcXM3ZEI.js";
2
2
  //#region src/core/cookies.d.ts
3
3
  declare function requestOrigin(request: Request): string;
4
4
  declare function sanitizeRedirectPath(rawRedirect: string | null | undefined, origin: string): string;
@@ -28,6 +28,16 @@ type GuardResult<Data> = {
28
28
  response: Response;
29
29
  };
30
30
  //#endregion
31
+ //#region src/core/resolve.d.ts
32
+ type SessionResolution<Data> = {
33
+ session: AccountsSession<Data> | null;
34
+ /**
35
+ * The Set-Cookie headers to attach to the response: the cache cookie while
36
+ * the session is alive, the cookies that clear a session that is gone.
37
+ */
38
+ cookies: string[];
39
+ };
40
+ //#endregion
31
41
  //#region src/core/store/memory.d.ts
32
42
  declare function createMemorySessionStore<Data>(): AccountsSessionStore<Data> & {
33
43
  rows: Map<string, AccountsSession<Data>>;
@@ -60,6 +70,7 @@ declare function createAccountsAuth<Data>(input: AccountsAuthConfig<Data>): {
60
70
  logout: (request: Request) => Promise<Response>;
61
71
  };
62
72
  guard: (request: Request, options?: GuardOptions) => Promise<GuardResult<Data>>;
73
+ resolveSession: (request: Request) => Promise<SessionResolution<Data>>;
63
74
  sessionFromCookie: (cookieValue: string | null) => Promise<AccountsSession<Data> | null>;
64
75
  sessionFromCookies: (cookies: SessionCookies) => Promise<AccountsSession<Data> | null>;
65
76
  sessionFromRequest: (request: Request) => Promise<AccountsSession<Data> | null>;
@@ -70,4 +81,4 @@ declare function createAccountsAuth<Data>(input: AccountsAuthConfig<Data>): {
70
81
  };
71
82
  type AccountsAuth<Data> = ReturnType<typeof createAccountsAuth<Data>>;
72
83
  //#endregion
73
- export { GuardOptions as a, accountsEndpoint as c, sanitizeRedirectPath as d, createMemorySessionStore as i, fetchUserInfo as l, SessionCookies as n, GuardResult as o, createAccountsAuth as r, cacheCookieBase as s, AccountsAuth as t, requestOrigin as u };
84
+ export { SessionResolution as a, cacheCookieBase as c, requestOrigin as d, sanitizeRedirectPath as f, createMemorySessionStore as i, accountsEndpoint as l, SessionCookies as n, GuardOptions as o, createAccountsAuth as r, GuardResult as s, AccountsAuth as t, fetchUserInfo as u };
package/dist/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- import { a as AccountsRequestError, c as AccountsSessionStore, d as OAuthTokenError, i as AccountsPaths, l as AccountsTokens, m as SignInInput, n as AccountsCacheConfig, o as AccountsSession, p as RevalidateInput, r as AccountsLifetimes, s as AccountsSessionPatch, t as AccountsAuthConfig, u as AccountsUser } from "./types-C79_29ZY.js";
2
- import { a as GuardOptions, c as accountsEndpoint, d as sanitizeRedirectPath, i as createMemorySessionStore, l as fetchUserInfo, n as SessionCookies, o as GuardResult, r as createAccountsAuth, s as cacheCookieBase, t as AccountsAuth, u as requestOrigin } from "./index-CiWgJQWW.js";
3
- export { AccountsAuth, type AccountsAuthConfig, type AccountsCacheConfig, type AccountsLifetimes, type AccountsPaths, AccountsRequestError, type AccountsSession, type AccountsSessionPatch, type AccountsSessionStore, type AccountsTokens, type AccountsUser, type GuardOptions, type GuardResult, OAuthTokenError, type RevalidateInput, SessionCookies, type SignInInput, accountsEndpoint, cacheCookieBase, createAccountsAuth, createMemorySessionStore, fetchUserInfo, requestOrigin, sanitizeRedirectPath };
1
+ import { a as AccountsRequestError, c as AccountsSessionStore, d as OAuthTokenError, i as AccountsPaths, l as AccountsTokens, m as SignInInput, n as AccountsCacheConfig, o as AccountsSession, p as RevalidateInput, r as AccountsLifetimes, s as AccountsSessionPatch, t as AccountsAuthConfig, u as AccountsUser } from "./types-BcXM3ZEI.js";
2
+ import { a as SessionResolution, c as cacheCookieBase, d as requestOrigin, f as sanitizeRedirectPath, i as createMemorySessionStore, l as accountsEndpoint, n as SessionCookies, o as GuardOptions, r as createAccountsAuth, s as GuardResult, t as AccountsAuth, u as fetchUserInfo } from "./index-CZZ3DRlf.js";
3
+ export { AccountsAuth, type AccountsAuthConfig, type AccountsCacheConfig, type AccountsLifetimes, type AccountsPaths, AccountsRequestError, type AccountsSession, type AccountsSessionPatch, type AccountsSessionStore, type AccountsTokens, type AccountsUser, type GuardOptions, type GuardResult, OAuthTokenError, type RevalidateInput, SessionCookies, type SessionResolution, type SignInInput, accountsEndpoint, cacheCookieBase, createAccountsAuth, createMemorySessionStore, fetchUserInfo, requestOrigin, sanitizeRedirectPath };
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import{C as e,E as t,S as n,T as r,_ as i,a,b as o,c as s,d as c,f as l,g as u,h as d,i as f,l as p,m,n as h,o as g,p as _,r as v,s as y,t as b,u as x,w as S,x as C,y as w}from"./cache-DuVjR2sZ.js";function T(t,r){return async function(e,i={}){let o=new URL(e.url);if((i.publicPaths??[t.paths.login,t.paths.callback,t.paths.error]).some(e=>o.pathname.startsWith(e)))return{kind:`ok`,session:null};let s=n(e,t.cookieName),c=n(e,h(t.cookieName)),l=await f(t,c,s,t.now());if(l)return{kind:`ok`,session:l};let u=s!==null||c!==null,d=await r.load(s);if(!d)return a(e,i,u);let p=d;try{let t=await r.revalidate(d);if(!t)return a(e,i,!0);p=t}catch{return{kind:`ok`,session:p}}if(p.tokens.accessTokenExpiresAt<=t.now()){let t=await r.ensureFreshTokens(p).catch(()=>p);if(!t)return a(e,i,!0);p=t}let m=await v(t,p,S(e),t.now());return m?{kind:`ok`,session:p,cookies:[m]}:{kind:`ok`,session:p}};function a(n,r,i){let a=S(n),s=new URL(n.url);if((r.apiPaths??[`/api`,`/trpc`]).some(e=>s.pathname.startsWith(e))){let e=Response.json({error:`Unauthorized`},{status:401});return i&&o(e,a),{kind:`response`,response:e}}let c=r.redirectPath?.(n)??`${s.pathname}${s.search}`,l=new URL(t.paths.login,a);l.searchParams.set(`redirect`,c),i&&l.searchParams.set(`silent`,`1`);let u=e(l);return i&&o(u,a),{kind:`response`,response:u}}function o(e,n){i(e.headers,t.cookieName,n);for(let r of b(t,n))e.headers.append(`set-cookie`,r)}}const E=/^[A-Za-z0-9_-]{1,128}$/,D=new Set([`login_required`,`consent_required`,`interaction_required`,`account_selection_required`]);function O(a,c){function l(e,t){let n=new URL(a.paths.login,e);return n.searchParams.set(`redirect`,t),n}function u(e,t,n){let r=new URL(a.paths.error,e);return r.searchParams.set(`reason`,t),n&&r.searchParams.set(`description`,n),r}async function f(n){let i=S(n),s=new URL(n.url).searchParams,c=r(s.get(`redirect`),i),l=s.get(`silent`)===`1`,{url:u,state:d,verifier:f}=await g(a,{origin:i,silent:l}),p=e(u);return t(p.headers,C(a.cookieName,d),o({verifier:f,redirectPath:c,silent:l}),i,a.lifetimes.flowMaxAgeMs),p}async function m(o){let f=S(o),m=new URL(o.url).searchParams,h=m.get(`state`),g=h&&E.test(h)?C(a.cookieName,h):null,y=g?w(n(o,g)):null,x=e=>(g&&i(e.headers,g,f),e);if(!y)return x(e(u(f,`invalid_state`,null)));let T=r(y.redirectPath,f),O=m.get(`error`);if(O)return y.silent&&D.has(O)?x(e(l(f,T))):x(e(u(f,O,m.get(`error_description`))));let k=m.get(`code`);if(!k)return x(e(u(f,`invalid_request`,null)));let A,j,M;try{let e=await s(a,{code:k,verifier:y.verifier,redirectUri:new URL(a.paths.callback,f).toString()});A=_(e,null,a.now()),j=await p(a,A.accessToken),M=await a.onSignIn({user:j,accessToken:A.accessToken,redirectPath:T,previous:null})}catch(t){return t instanceof d?x(e(u(f,t.code,t.description||null))):x(e(u(f,`accounts_unavailable`,null)))}if(M===null){let t=e(u(f,`access_denied`,null)),r=n(o,a.cookieName),s=await c.load(r);s&&await c.end(s),r!==null&&i(t.headers,a.cookieName,f);for(let e of b(a,f))t.headers.append(`set-cookie`,e);return x(t)}let N,P;try{({cookieValue:N,session:P}=await c.start({user:j,tokens:A,data:M}))}catch{return x(e(u(f,`session_store_error`,null)))}let F=e(new URL(T,f));t(F.headers,a.cookieName,N,f,a.lifetimes.absoluteMaxAgeMs);let I=await v(a,P,f,a.now()).catch(()=>null);return I&&F.headers.append(`set-cookie`,I),x(F)}async function h(t){let r=S(t),o=await c.load(n(t,a.cookieName));o&&await c.end(o);let s=o?.tokens.idToken?y(a,{origin:r,idToken:o.tokens.idToken}):new URL(a.paths.logoutComplete,r).toString(),l=e(s,303);i(l.headers,a.cookieName,r);for(let e of b(a,r))l.headers.append(`set-cookie`,e);return l}return{login:f,callback:m,logout:h}}const k=e=>new Promise(t=>setTimeout(t,e));function A(e){let{store:t,lifetimes:n}=e;function r(e,t){return t-e.createdAt>=n.absoluteMaxAgeMs||t-e.lastValidatedAt>=n.idleMaxAgeMs}function i(e,t){return e.accessTokenExpiresAt-t<=n.refreshBeforeExpiryMs}async function a(n){if(!n)return null;let i=await t.read(await l(n));return i?r(i,e.now())?(await t.delete(i.id),null):i:null}async function o(n){let r=x(32),i=e.now(),a={id:await l(r),user:n.user,tokens:n.tokens,data:n.data,createdAt:i,lastValidatedAt:i,refreshLeaseUntil:null};return await t.create(a),{session:a,cookieValue:r}}async function s(r){let a=e.now();if(!i(r.tokens,a))return r;if(!r.tokens.refreshToken)return await t.delete(r.id),null;let o=await t.claimRefreshLease(r.id,a+n.refreshLeaseMs,a);if(!o)return u(r.id,a);let s=o.refreshLeaseUntil??void 0;if(!i(o.tokens,a))return await t.update(o.id,{refreshLeaseUntil:null},s)??t.read(o.id);try{let r=await c(e,o.tokens.refreshToken,Math.max(n.refreshLeaseMs-1e3,n.refreshLeaseMs/2));return await t.update(o.id,{tokens:_(r,o.tokens,e.now()),refreshLeaseUntil:null},s)??t.read(o.id)}catch(n){if(n instanceof d&&n.code===`invalid_grant`)return await t.delete(o.id,s),await t.read(o.id)??null;let r=await t.update(o.id,{refreshLeaseUntil:null},s);if(o.tokens.accessTokenExpiresAt>e.now())return r??o;throw n}}async function u(r,a){for(;;){await k(100);let o=await t.read(r);if(!o)return null;let c=e.now();if(!i(o.tokens,c))return o;if(o.refreshLeaseUntil===null||o.refreshLeaseUntil<=c)return s(o);if(c-a>=n.leaseWaitMs){if(o.tokens.accessTokenExpiresAt>c)return o;throw new m(`Timed out waiting for the session refresh lease`,0)}}}async function f(r){if(e.now()-r.lastValidatedAt<n.revalidateIntervalMs)return r;let i=await s(r);if(!i)return null;let a=await e.onRevalidate({session:i,accessToken:i.tokens.accessToken});return a===null?(await t.delete(i.id),null):t.update(i.id,{data:a,lastValidatedAt:e.now()})}async function p(e){await t.delete(e.id)}return{load:a,start:o,ensureFreshTokens:s,revalidate:f,end:p}}function j(){let e=new Map;return{rows:e,async create(t){e.set(t.id,structuredClone(t))},async read(t){let n=e.get(t);return n?structuredClone(n):null},async update(t,n,r){let i=e.get(t);if(!i||r!==void 0&&i.refreshLeaseUntil!==r)return null;let a=structuredClone({...i,...n});return e.set(t,a),structuredClone(a)},async claimRefreshLease(t,n,r){let i=e.get(t);if(!i||i.refreshLeaseUntil!==null&&i.refreshLeaseUntil>r)return null;let a={...i,refreshLeaseUntil:n};return e.set(t,a),structuredClone(a)},async delete(t,n){let r=e.get(t);r&&(n===void 0||r.refreshLeaseUntil===n)&&e.delete(t)}}}function M(e){let t=u(e),r=A(t),i=O(t,r),a=T(t,r);function o(e){return{session:n(e,t.cookieName),cache:n(e,h(t.cookieName))}}async function s(e){return r.load(e)}async function c(e){return await f(t,e.cache,e.session,t.now())??r.load(e.session)}async function l(e){return c(o(e))}async function d(e){let t=await r.load(e);return t?(await r.ensureFreshTokens(t))?.tokens.accessToken??null:null}async function p(e){let n=await f(t,e.cache,e.session,t.now());return n&&n.tokens.accessTokenExpiresAt-t.now()>t.lifetimes.refreshBeforeExpiryMs?n.tokens.accessToken:d(e.session)}async function m(e){return p(o(e))}async function g(e,n){let i=await r.load(e);return i?t.store.update(i.id,{data:n(i.data)}):null}return{config:t,sessions:r,handlers:i,guard:a,sessionFromCookie:s,sessionFromCookies:c,sessionFromRequest:l,accessTokenFromCookie:d,accessTokenFromCookies:p,accessTokenFromRequest:m,updateSessionData:g}}export{m as AccountsRequestError,d as OAuthTokenError,a as accountsEndpoint,h as cacheCookieBase,M as createAccountsAuth,j as createMemorySessionStore,p as fetchUserInfo,S as requestOrigin,r as sanitizeRedirectPath};
1
+ import{C as e,D as t,E as n,S as r,T as i,_ as a,a as o,b as s,c,d as l,f as u,g as d,h as f,i as p,l as m,m as h,n as g,o as _,p as v,r as y,s as b,t as x,u as S,v as C,w,x as T}from"./cache-BWpH93Oi.js";function E(e,t){return[...C(e.cookieName,t),...x(e,t)]}function D(t,n){return async function(r){let a=i(r),o=e(r,t.cookieName),s=e(r,g(t.cookieName)),c=await p(t,s,o,t.now());if(c)return{session:c,cookies:[]};let l={session:null,cookies:o!==null||s!==null?E(t,a):[]},u=await n.load(o);if(!u)return l;let d=u;try{let e=await n.revalidate(u);if(!e)return l;d=e}catch{return{session:d,cookies:[]}}if(d.tokens.accessTokenExpiresAt<=t.now()){let e=await n.ensureFreshTokens(d).catch(()=>d);if(!e)return l;d=e}let f=await y(t,d,a,t.now());return{session:d,cookies:f?[f]:[]}}}function O(e,t){let n=D(e,t);return async function(t,i={}){let a=new URL(t.url);if((i.publicPaths??[e.paths.login,e.paths.callback,e.paths.error]).some(e=>a.pathname.startsWith(e)))return{kind:`ok`,session:null};let{session:o,cookies:s}=await n(t);return o?s.length>0?{kind:`ok`,session:o,cookies:s}:{kind:`ok`,session:o}:r(t,i,s)};function r(e,t,n){let r=n.length>0,i=new URL(e.url),o=(t.apiPaths??[`/api`,`/trpc`]).some(e=>i.pathname.startsWith(e))?Response.json({error:`Unauthorized`},{status:401}):w(a(e,t,r));for(let e of n)o.headers.append(`set-cookie`,e);return{kind:`response`,response:o}}function a(t,n,r){let a=new URL(t.url),o=new URL(e.paths.login,i(t));return o.searchParams.set(`redirect`,n.redirectPath?.(t)??`${a.pathname}${a.search}`),r&&o.searchParams.set(`silent`,`1`),o}}const k=/^[A-Za-z0-9_-]{1,128}$/,A=new Set([`login_required`,`consent_required`,`interaction_required`,`account_selection_required`]);function j(o,l){function u(e,t){let n=new URL(o.paths.login,e);return n.searchParams.set(`redirect`,t),n}function d(e,t,n){let r=new URL(o.paths.error,e);return r.searchParams.set(`reason`,t),n&&r.searchParams.set(`description`,n),r}async function p(e){let a=i(e),s=new URL(e.url).searchParams,c=n(s.get(`redirect`),a),l=s.get(`silent`)===`1`,{url:u,state:d,verifier:f}=await _(o,{origin:a,silent:l}),p=w(u);return t(p.headers,r(o.cookieName,d),T({verifier:f,redirectPath:c,silent:l}),a,o.lifetimes.flowMaxAgeMs),p}async function h(p){let h=i(p),g=new URL(p.url).searchParams,_=g.get(`state`),b=_&&k.test(_)?r(o.cookieName,_):null,S=b?s(e(p,b)):null,C=e=>(b&&a(e.headers,b,h),e);if(!S)return C(w(d(h,`invalid_state`,null)));let T=n(S.redirectPath,h),E=g.get(`error`);if(E)return S.silent&&A.has(E)?C(w(u(h,T))):C(w(d(h,E,g.get(`error_description`))));let D=g.get(`code`);if(!D)return C(w(d(h,`invalid_request`,null)));let O,j,M;try{let e=await c(o,{code:D,verifier:S.verifier,redirectUri:new URL(o.paths.callback,h).toString()});O=v(e,null,o.now()),j=await m(o,O.accessToken),M=await o.onSignIn({user:j,accessToken:O.accessToken,redirectPath:T,previous:null})}catch(e){return e instanceof f?C(w(d(h,e.code,e.description||null))):C(w(d(h,`accounts_unavailable`,null)))}if(M===null){let t=w(d(h,`access_denied`,null)),n=e(p,o.cookieName),r=await l.load(n);r&&await l.end(r),n!==null&&a(t.headers,o.cookieName,h);for(let e of x(o,h))t.headers.append(`set-cookie`,e);return C(t)}let N,P;try{({cookieValue:N,session:P}=await l.start({user:j,tokens:O,data:M}))}catch{return C(w(d(h,`session_store_error`,null)))}let F=w(new URL(T,h));t(F.headers,o.cookieName,N,h,o.lifetimes.absoluteMaxAgeMs);let I=await y(o,P,h,o.now()).catch(()=>null);return I&&F.headers.append(`set-cookie`,I),C(F)}async function g(t){let n=i(t),r=await l.load(e(t,o.cookieName));r&&await l.end(r);let a=r?.tokens.idToken?b(o,{origin:n,idToken:r.tokens.idToken}):new URL(o.paths.logoutComplete,n).toString(),s=w(a,303);for(let e of E(o,n))s.headers.append(`set-cookie`,e);return s}return{login:p,callback:h,logout:g}}const M=e=>new Promise(t=>setTimeout(t,e));function N(e){let{store:t,lifetimes:n}=e;function r(e,t){return t-e.createdAt>=n.absoluteMaxAgeMs||t-e.lastValidatedAt>=n.idleMaxAgeMs}function i(e,t){return e.accessTokenExpiresAt-t<=n.refreshBeforeExpiryMs}async function a(n){if(!n)return null;let i=await t.read(await u(n));return i?r(i,e.now())?(await t.delete(i.id),null):i:null}async function o(n){let r=S(32),i=e.now(),a={id:await u(r),user:n.user,tokens:n.tokens,data:n.data,createdAt:i,lastValidatedAt:i,refreshLeaseUntil:null};return await t.create(a),{session:a,cookieValue:r}}async function s(r){let a=e.now();if(!i(r.tokens,a))return r;if(!r.tokens.refreshToken)return await t.delete(r.id),null;let o=await t.claimRefreshLease(r.id,a+n.refreshLeaseMs,a);if(!o)return c(r.id,a);let s=o.refreshLeaseUntil??void 0;if(!i(o.tokens,a))return await t.update(o.id,{refreshLeaseUntil:null},s)??t.read(o.id);try{let r=await l(e,o.tokens.refreshToken,Math.max(n.refreshLeaseMs-1e3,n.refreshLeaseMs/2));return await t.update(o.id,{tokens:v(r,o.tokens,e.now()),refreshLeaseUntil:null},s)??t.read(o.id)}catch(n){if(n instanceof f&&n.code===`invalid_grant`)return await t.delete(o.id,s)?null:await t.read(o.id)??null;let r=await t.update(o.id,{refreshLeaseUntil:null},s);if(o.tokens.accessTokenExpiresAt>e.now())return r??o;throw n}}async function c(r,a){for(;;){await M(100);let o=await t.read(r);if(!o)return null;let c=e.now();if(!i(o.tokens,c))return o;if(o.refreshLeaseUntil===null||o.refreshLeaseUntil<=c)return s(o);if(c-a>=n.leaseWaitMs){if(o.tokens.accessTokenExpiresAt>c)return o;throw new h(`Timed out waiting for the session refresh lease`,0)}}}async function d(r){if(e.now()-r.lastValidatedAt<n.revalidateIntervalMs)return r;let i=await s(r);if(!i)return null;let a=await e.onRevalidate({session:i,accessToken:i.tokens.accessToken});return a===null?(await t.delete(i.id),null):t.update(i.id,{data:a,lastValidatedAt:e.now()})}async function p(e){await t.delete(e.id)}return{load:a,start:o,ensureFreshTokens:s,revalidate:d,end:p}}function P(){let e=new Map;return{rows:e,async create(t){e.set(t.id,structuredClone(t))},async read(t){let n=e.get(t);return n?structuredClone(n):null},async update(t,n,r){let i=e.get(t);if(!i||r!==void 0&&i.refreshLeaseUntil!==r)return null;let a=structuredClone({...i,...n});return e.set(t,a),structuredClone(a)},async claimRefreshLease(t,n,r){let i=e.get(t);if(!i||i.refreshLeaseUntil!==null&&i.refreshLeaseUntil>r)return null;let a={...i,refreshLeaseUntil:n};return e.set(t,a),structuredClone(a)},async delete(t,n){let r=e.get(t);return!r||n!==void 0&&r.refreshLeaseUntil!==n?!1:(e.delete(t),!0)}}}function F(t){let n=d(t),r=N(n),i=j(n,r),a=O(n,r),o=D(n,r);function s(t){return{session:e(t,n.cookieName),cache:e(t,g(n.cookieName))}}async function c(e){return r.load(e)}async function l(e){return await p(n,e.cache,e.session,n.now())??r.load(e.session)}async function u(e){return l(s(e))}async function f(e){let t=await r.load(e);return t?(await r.ensureFreshTokens(t))?.tokens.accessToken??null:null}async function m(e){let t=await p(n,e.cache,e.session,n.now());return t&&t.tokens.accessTokenExpiresAt-n.now()>n.lifetimes.refreshBeforeExpiryMs?t.tokens.accessToken:f(e.session)}async function h(e){return m(s(e))}async function _(e,t){let i=await r.load(e);return i?n.store.update(i.id,{data:t(i.data)}):null}return{config:n,sessions:r,handlers:i,guard:a,resolveSession:o,sessionFromCookie:c,sessionFromCookies:l,sessionFromRequest:u,accessTokenFromCookie:f,accessTokenFromCookies:m,accessTokenFromRequest:h,updateSessionData:_}}export{h as AccountsRequestError,f as OAuthTokenError,o as accountsEndpoint,g as cacheCookieBase,F as createAccountsAuth,P as createMemorySessionStore,m as fetchUserInfo,i as requestOrigin,n as sanitizeRedirectPath};
package/dist/next.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { o as AccountsSession } from "./types-C79_29ZY.js";
2
- import { t as AccountsAuth } from "./index-CiWgJQWW.js";
1
+ import { o as AccountsSession } from "./types-BcXM3ZEI.js";
2
+ import { t as AccountsAuth } from "./index-CZZ3DRlf.js";
3
3
  //#region src/next/index.d.ts
4
4
  declare function withNextRequestScope<Data>(auth: AccountsAuth<Data>): {
5
5
  getSession(): Promise<AccountsSession<Data> | null>;
package/dist/next.js CHANGED
@@ -1 +1 @@
1
- import{n as e,v as t}from"./cache-DuVjR2sZ.js";import{cookies as n}from"next/headers";async function r(r){let i=await n(),a=e=>i.get(t(e,!0))?.value||i.get(t(e,!1))?.value||null;return{session:a(r),cache:a(e(r))}}async function i(r){let i=await n(),a=e(r);for(let e of[t(a,!0),t(a,!1)])try{i.delete(e)}catch{}}function a(e){let t=e.config.cookieName;return{async getSession(){return e.sessionFromCookies(await r(t))},async getAccessToken(){return e.accessTokenFromCookies(await r(t))},async updateSessionData(n){let a=await e.updateSessionData((await r(t)).session,n);return a&&await i(t),a}}}export{a as withNextRequestScope};
1
+ import{n as e,y as t}from"./cache-BWpH93Oi.js";import{cookies as n}from"next/headers";import{connection as r}from"next/server";async function i(i){await r();let a=await n(),o=e=>a.get(t(e,!0))?.value||a.get(t(e,!1))?.value||null;return{session:o(i),cache:o(e(i))}}async function a(r){let i=await n(),a=e(r);for(let e of[t(a,!0),t(a,!1)])try{i.delete(e)}catch{}}function o(e){let t=e.config.cookieName;return{async getSession(){return e.sessionFromCookies(await i(t))},async getAccessToken(){return e.accessTokenFromCookies(await i(t))},async updateSessionData(n){let r=await e.updateSessionData((await i(t)).session,n);return r&&await a(t),r}}}export{o as withNextRequestScope};
@@ -0,0 +1,35 @@
1
+ import { c as AccountsSessionStore } from "./types-BcXM3ZEI.js";
2
+ //#region src/testing/index.d.ts
3
+ /**
4
+ * A behavioural conformance suite for the session store contract.
5
+ *
6
+ * The store is the one piece every deployment reimplements, and its hardest
7
+ * part is invisible from the type: the takeover comparison in
8
+ * `claimRefreshLease` is not the equality fence `update` and `delete` use,
9
+ * and getting it wrong means two workers refresh at once, which accounts
10
+ * answers by revoking the whole token family. This suite is the contract, so
11
+ * a new store is checked rather than derived by reading the shipped ones.
12
+ *
13
+ * It returns cases instead of registering them, so it runs under node:test,
14
+ * vitest, or anything else:
15
+ *
16
+ * ```ts
17
+ * for (const c of sessionStoreConformance({ createStore })) {
18
+ * test(c.name, c.run);
19
+ * }
20
+ * ```
21
+ */
22
+ type ConformanceCase = {
23
+ name: string;
24
+ run: () => Promise<void>;
25
+ };
26
+ type StoreConformanceOptions<Data> = {
27
+ /** A store backed by empty storage. Called once per case. */
28
+ createStore: () => AccountsSessionStore<Data> | Promise<AccountsSessionStore<Data>>;
29
+ /** Two distinguishable app payloads. Defaults suit a store generic in Data. */
30
+ data?: Data;
31
+ otherData?: Data;
32
+ };
33
+ declare function sessionStoreConformance<Data = Record<string, never>>(options: StoreConformanceOptions<Data>): ConformanceCase[];
34
+ //#endregion
35
+ export { ConformanceCase, StoreConformanceOptions, sessionStoreConformance };
@@ -0,0 +1 @@
1
+ import e from"node:assert/strict";const t=17e11;function n(e,n){return{id:e,user:{id:`user_1`,email:`u@test`,name:`U`,image:null},tokens:{accessToken:`at_1`,refreshToken:`rt_1`,idToken:`idt_1`,accessTokenExpiresAt:17000036e5},data:n,createdAt:t,lastValidatedAt:t,refreshLeaseUntil:null}}function r(r){let i=r.data??{seed:1},a=r.otherData??{seed:2},o=()=>Promise.resolve(r.createStore()),s=async(e=`sess_1`)=>{let t=await o();return await t.create(n(e,i)),t};return[{name:`read returns every field create was given`,run:async()=>{let t=await s();e.deepEqual(await t.read(`sess_1`),n(`sess_1`,i))}},{name:`read answers null for an id that was never created`,run:async()=>{let t=await o();e.equal(await t.read(`missing`),null)}},{name:`create keeps a null refresh token null rather than empty`,run:async()=>{let t=await o(),r=n(`sess_1`,i);r.tokens={...r.tokens,refreshToken:null,idToken:null},await t.create(r);let a=await t.read(`sess_1`);e.equal(a?.tokens.refreshToken,null),e.equal(a?.tokens.idToken,null)}},{name:`update writes only the patched fields`,run:async()=>{let n=await(await s()).update(`sess_1`,{data:a});e.deepEqual(n?.data,a),e.equal(n?.lastValidatedAt,t),e.equal(n?.tokens.accessToken,`at_1`)}},{name:`update answers null for an id that is not there`,run:async()=>{let t=await o();e.equal(await t.update(`missing`,{lastValidatedAt:1}),null)}},{name:`update applies when ifLeaseUntil is the lease on the row`,run:async()=>{let n=await s();await n.claimRefreshLease(`sess_1`,170000002e4,t);let r=await n.update(`sess_1`,{lastValidatedAt:1700000000005},170000002e4);e.equal(r?.lastValidatedAt,1700000000005)}},{name:`update writes nothing when ifLeaseUntil is not the lease on the row`,run:async()=>{let n=await s();await n.claimRefreshLease(`sess_1`,170000002e4,t);let r=await n.update(`sess_1`,{lastValidatedAt:1700000000005},1700000999999);e.equal(r,null),e.equal((await n.read(`sess_1`))?.lastValidatedAt,t)}},{name:`update releases the lease when the patch sets it null`,run:async()=>{let n=await s();await n.claimRefreshLease(`sess_1`,170000002e4,t),await n.update(`sess_1`,{refreshLeaseUntil:null},170000002e4),e.equal((await n.read(`sess_1`))?.refreshLeaseUntil,null)}},{name:`claimRefreshLease takes a lease when the row holds none`,run:async()=>{let n=await s(),r=await n.claimRefreshLease(`sess_1`,170000002e4,t);e.equal(r?.refreshLeaseUntil,170000002e4),e.equal((await n.read(`sess_1`))?.refreshLeaseUntil,170000002e4)}},{name:`claimRefreshLease refuses while another lease is still live`,run:async()=>{let n=await s();await n.claimRefreshLease(`sess_1`,170000002e4,t),e.equal(await n.claimRefreshLease(`sess_1`,170000004e4,1700000001e3),null),e.equal((await n.read(`sess_1`))?.refreshLeaseUntil,170000002e4)}},{name:`claimRefreshLease takes over a lease that has expired`,run:async()=>{let n=await s();await n.claimRefreshLease(`sess_1`,170000002e4,t);let r=await n.claimRefreshLease(`sess_1`,170000006e4,1700000020001);e.equal(r?.refreshLeaseUntil,170000006e4)}},{name:`claimRefreshLease answers null for an id that is not there`,run:async()=>{let n=await o();e.equal(await n.claimRefreshLease(`missing`,170000002e4,t),null)}},{name:`delete without a lease removes the session and reports true`,run:async()=>{let t=await s();e.equal(await t.delete(`sess_1`),!0),e.equal(await t.read(`sess_1`),null)}},{name:`delete reports false for an id that is not there`,run:async()=>{let t=await o();e.equal(await t.delete(`missing`),!1)}},{name:`delete applies when ifLeaseUntil is the lease on the row`,run:async()=>{let n=await s();await n.claimRefreshLease(`sess_1`,170000002e4,t),e.equal(await n.delete(`sess_1`,170000002e4),!0),e.equal(await n.read(`sess_1`),null)}},{name:`delete keeps the session when ifLeaseUntil is not its lease`,run:async()=>{let n=await s();await n.claimRefreshLease(`sess_1`,170000002e4,t),e.equal(await n.delete(`sess_1`,1700000999999),!1),e.notEqual(await n.read(`sess_1`),null)}},{name:`sessions are addressed independently`,run:async()=>{let t=await s(`sess_1`);await t.create(n(`sess_2`,a)),await t.delete(`sess_1`),e.equal(await t.read(`sess_1`),null),e.deepEqual((await t.read(`sess_2`))?.data,a)}}]}export{r as sessionStoreConformance};
@@ -33,7 +33,13 @@ interface AccountsSessionStore<Data> {
33
33
  read(id: string): Promise<AccountsSession<Data> | null>;
34
34
  update(id: string, patch: AccountsSessionPatch<Data>, ifLeaseUntil?: number): Promise<AccountsSession<Data> | null>;
35
35
  claimRefreshLease(id: string, until: number, now: number): Promise<AccountsSession<Data> | null>;
36
- delete(id: string, ifLeaseUntil?: number): Promise<void>;
36
+ /**
37
+ * Removes the session. With `ifLeaseUntil`, removes it only while that
38
+ * refresh lease is still the one on the row, and resolves false when it is
39
+ * not, so a refresher that lost its lease can tell the difference between
40
+ * "gone" and "someone else owns it".
41
+ */
42
+ delete(id: string, ifLeaseUntil?: number): Promise<boolean>;
37
43
  }
38
44
  type AccountsPaths = {
39
45
  login: string;
@@ -70,8 +76,17 @@ type AccountsAuthConfig<Data> = {
70
76
  store: AccountsSessionStore<Data>;
71
77
  paths?: Partial<AccountsPaths>;
72
78
  lifetimes?: Partial<AccountsLifetimes>;
73
- onSignIn(input: SignInInput<Data>): Promise<Data | null>;
74
- onRevalidate(input: RevalidateInput<Data>): Promise<Data | null>;
79
+ /**
80
+ * Returns the app data to store on the session, or null to deny the sign-in.
81
+ * Omit it when the app keeps nothing of its own on the session.
82
+ */
83
+ onSignIn?(input: SignInInput<Data>): Promise<Data | null>;
84
+ /**
85
+ * Re-derives the app data, or returns null to end the session. Throwing
86
+ * keeps it, because a failure to reach accounts says nothing about the user.
87
+ * Omit it when the app keeps nothing of its own on the session.
88
+ */
89
+ onRevalidate?(input: RevalidateInput<Data>): Promise<Data | null>;
75
90
  fetch?: typeof fetch;
76
91
  now?: () => number;
77
92
  cache?: AccountsCacheConfig;
@@ -81,7 +96,9 @@ type AccountsCacheConfig = {
81
96
  secret: string;
82
97
  maxAgeMs?: number;
83
98
  };
84
- type ResolvedAccountsAuthConfig<Data> = Omit<AccountsAuthConfig<Data>, "paths" | "lifetimes" | "scope" | "fetch" | "now" | "cache" | "audience"> & {
99
+ type ResolvedAccountsAuthConfig<Data> = Omit<AccountsAuthConfig<Data>, "paths" | "lifetimes" | "scope" | "fetch" | "now" | "cache" | "audience" | "onSignIn" | "onRevalidate"> & {
100
+ onSignIn(input: SignInInput<Data>): Promise<Data | null>;
101
+ onRevalidate(input: RevalidateInput<Data>): Promise<Data | null>;
85
102
  scope: string;
86
103
  paths: AccountsPaths;
87
104
  lifetimes: AccountsLifetimes;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aui-auth",
3
- "version": "0.0.3",
3
+ "version": "0.0.4",
4
4
  "description": "Server side sessions for web apps that sign in through assistant-ui accounts: OIDC code flow with PKCE, tokens kept in the app's database, single flight refresh",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -28,6 +28,14 @@
28
28
  "./database/pg": {
29
29
  "types": "./dist/database/pg.d.ts",
30
30
  "default": "./dist/database/pg.js"
31
+ },
32
+ "./database/redis": {
33
+ "types": "./dist/database/redis.d.ts",
34
+ "default": "./dist/database/redis.js"
35
+ },
36
+ "./testing": {
37
+ "types": "./dist/testing.d.ts",
38
+ "default": "./dist/testing.js"
31
39
  }
32
40
  },
33
41
  "peerDependencies": {
@@ -40,6 +48,7 @@
40
48
  },
41
49
  "devDependencies": {
42
50
  "@types/node": "^26.1.2",
51
+ "ioredis": "^6.0.0",
43
52
  "next": "^16.3.0",
44
53
  "tsdown": "^0.22.14",
45
54
  "typescript": "^7.0.2"
@@ -1 +0,0 @@
1
- import{t as e}from"./codec-BcgaGRoP.js";function t(e){if(!e)return;let t=e.split(`,`);return t[t.length-1].trim()||void 0}function n(e){let n=new URL(e.url);return`${t(e.headers.get(`x-forwarded-proto`))||n.protocol.replace(`:`,``)}://${t(e.headers.get(`x-forwarded-host`))||e.headers.get(`host`)||n.host}`}function r(e){return new URL(e).protocol===`https:`}function i(e,t){return t?`__Secure-${e}`:e}function a(e){let t=new Map;if(!e)return t;for(let n of e.split(`;`)){let e=n.indexOf(`=`);if(e===-1)continue;let r=n.slice(0,e).trim();!r||t.has(r)||t.set(r,n.slice(e+1).trim())}return t}function o(e,t){let n=a(e.headers.get(`cookie`));return n.get(i(t,!0))||n.get(i(t,!1))||null}function s(e,t,n,r){let i=[`${e}=${t}`,`Path=/`,`HttpOnly`,`SameSite=Lax`,`Max-Age=${r}`];return n&&i.push(`Secure`),i.join(`; `)}function c(e,t,n,a,o){let c=r(a);e.append(`set-cookie`,s(i(t,c),n,c,Math.floor(o/1e3)))}function l(e,t,n){let a=r(n);for(let n of[a,!a])e.append(`set-cookie`,s(i(t,n),``,n,0))}function u(e,t=307){return new Response(null,{status:t,headers:{location:e.toString()}})}function d(e,t){return`${e}_flow_${t}`}function f(e){return btoa(JSON.stringify(e)).replace(/\+/g,`-`).replace(/\//g,`_`).replace(/=+$/g,``)}function p(e){if(!e)return null;try{let t=e.replace(/-/g,`+`).replace(/_/g,`/`),n=JSON.parse(atob(t));return typeof n.verifier==`string`?{verifier:n.verifier,redirectPath:typeof n.redirectPath==`string`?n.redirectPath:`/`,silent:n.silent===!0}:null}catch{return null}}function m(e,t){if(!e)return`/`;let n;try{n=new URL(e,t)}catch{return`/`}return n.origin===t?`${n.pathname}${n.search}${n.hash}`:`/`}const h={login:`/api/auth/login`,callback:`/api/auth/callback`,logout:`/api/auth/logout`,logoutComplete:`/api/auth/logout-complete`,error:`/auth/error`},g={absoluteMaxAgeMs:2592e6,idleMaxAgeMs:6048e5,revalidateIntervalMs:12e4,refreshBeforeExpiryMs:3e5,flowMaxAgeMs:6e5,refreshLeaseMs:2e4,leaseWaitMs:5e3};function _(e){return{...e,scope:e.scope??`openid profile email offline_access`,paths:{...h,...e.paths},lifetimes:{...g,...e.lifetimes},fetch:e.fetch??globalThis.fetch.bind(globalThis),now:e.now??Date.now,cache:e.cache?{codec:N(e.cache.secret),maxAgeMs:e.cache.maxAgeMs??6e4}:null,audience:e.audience===!1?null:e.audience??new URL(`/api/auth`,e.issuer).toString()}}var v=class extends Error{status;constructor(e,t){super(e),this.name=`AccountsRequestError`,this.status=t}},y=class extends v{code;description;constructor(e,t,n){super(`Token request failed: ${e} ${t} ${n}`,e),this.name=`OAuthTokenError`,this.code=t,this.description=n}};function b(e){let t=``;for(let n of e)t+=String.fromCharCode(n);return btoa(t).replace(/\+/g,`-`).replace(/\//g,`_`).replace(/=+$/g,``)}function x(e){return b(crypto.getRandomValues(new Uint8Array(e)))}async function S(e){let t=await crypto.subtle.digest(`SHA-256`,new TextEncoder().encode(e));return b(new Uint8Array(t))}function C(e,t){return new URL(t,e).toString()}async function w(e,t){let n=x(24),r=x(32),i=new URL(C(e.issuer,`/api/auth/oauth2/authorize`));return i.searchParams.set(`client_id`,e.clientId),i.searchParams.set(`redirect_uri`,new URL(e.paths.callback,t.origin).toString()),i.searchParams.set(`response_type`,`code`),i.searchParams.set(`scope`,e.scope),i.searchParams.set(`state`,n),i.searchParams.set(`code_challenge`,await S(r)),i.searchParams.set(`code_challenge_method`,`S256`),t.silent&&i.searchParams.set(`prompt`,`none`),{url:i.toString(),state:n,verifier:r}}function T(e,t){let n=new URL(C(e.issuer,`/api/auth/oauth2/end-session`));return n.searchParams.set(`id_token_hint`,t.idToken),n.searchParams.set(`client_id`,e.clientId),n.searchParams.set(`post_logout_redirect_uri`,new URL(e.paths.logoutComplete,t.origin).toString()),n.toString()}async function E(e,t,n,r=!0){let i=new URLSearchParams({client_id:e.clientId,...t});e.clientSecret&&i.set(`client_secret`,e.clientSecret),e.audience&&r&&i.set(`resource`,e.audience);let a=n===void 0?void 0:n-Date.now();if(a!==void 0&&a<=0)throw new v(`Token request deadline passed`,0);let o=await e.fetch(C(e.issuer,`/api/auth/oauth2/token`),{method:`POST`,headers:{"Content-Type":`application/x-www-form-urlencoded`},body:i,cache:`no-store`,...a?{signal:AbortSignal.timeout(a)}:{}});if(!o.ok){let i=await o.text().catch(()=>``),a=`unknown_error`,s=i;try{let e=JSON.parse(i);a=e.error??a,s=e.error_description??s}catch{}if(r&&e.audience&&a===`invalid_request`&&/resource/i.test(s))return E(e,t,n,!1);throw new y(o.status,a,s)}return await o.json()}function D(e,t){return E(e,{grant_type:`authorization_code`,code:t.code,code_verifier:t.verifier,redirect_uri:t.redirectUri})}function O(e,t,n){return E(e,{grant_type:`refresh_token`,refresh_token:t},n===void 0?void 0:Date.now()+n)}async function k(e,t){let n=await(e.fetch??globalThis.fetch.bind(globalThis))(C(e.issuer,`/api/auth/oauth2/userinfo`),{headers:{Authorization:`Bearer ${t}`},cache:`no-store`});if(!n.ok)throw new v(`Failed to load user info: ${n.status}`,n.status);let r=await n.json();return{id:r.sub,email:r.email??``,name:r.name??r.email??r.sub,image:r.picture??null}}function A(e,t,n){return{accessToken:e.access_token,refreshToken:e.refresh_token??t?.refreshToken??null,idToken:e.id_token??t?.idToken??null,accessTokenExpiresAt:typeof e.expires_at==`number`?e.expires_at*1e3:n+(e.expires_in??3600)*1e3}}function j(e){return`${e}_cache`}function M(e){let t=``;for(let n of e)t+=n.toString(16).padStart(2,`0`);return t}function N(t){let n=null;return()=>n??=crypto.subtle.digest(`SHA-256`,new TextEncoder().encode(t)).then(t=>e(M(new Uint8Array(t))))}function P(e,t,n){if(!e.cache)return 0;let{lifetimes:r}=e;return Math.min(e.cache.maxAgeMs,t.lastValidatedAt+r.revalidateIntervalMs-n,t.tokens.accessTokenExpiresAt-r.refreshBeforeExpiryMs-n,t.createdAt+r.absoluteMaxAgeMs-n,t.lastValidatedAt+r.idleMaxAgeMs-n)}async function F(e,t,n){if(!e.cache)return null;let r=P(e,t,n);if(r<1e3)return null;let i={v:1,id:t.id,u:t.user,d:t.data,at:t.tokens.accessToken,ate:t.tokens.accessTokenExpiresAt,ca:t.createdAt,lv:t.lastValidatedAt,exp:n+r};return{value:await(await e.cache.codec()).encrypt(JSON.stringify(i)),maxAgeMs:r}}async function I(e,t,n,r){if(!e.cache||!t||!n)return null;let i;try{let n=await e.cache.codec();i=JSON.parse(await n.decrypt(t))}catch{return null}return i.v!==1||typeof i.exp!=`number`||i.exp<=r||i.id!==await S(n)?null:{id:i.id,user:i.u,tokens:{accessToken:i.at,refreshToken:null,idToken:null,accessTokenExpiresAt:i.ate},data:i.d,createdAt:i.ca,lastValidatedAt:i.lv,refreshLeaseUntil:null}}async function L(e,t,n,a){let o=await F(e,t,a);if(!o)return null;let c=r(n);return s(i(j(e.cookieName),c),o.value,c,Math.floor(o.maxAgeMs/1e3))}function R(e,t){if(!e.cache)return[];let n=r(t),a=j(e.cookieName);return[n,!n].map(e=>s(i(a,e),``,e,0))}export{u as C,c as E,o as S,m as T,l as _,C as a,f as b,D as c,O as d,S as f,_ as g,y as h,I as i,k as l,v as m,j as n,w as o,A as p,L as r,T as s,R as t,x as u,i as v,n as w,d as x,p as y};