@tktchurch/auth 0.9.9 → 0.11.0

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.
@@ -0,0 +1,289 @@
1
+ import { i as AuthorizationUrlOptions, a as AuthClient, h as AuthorizationRequest } from './types-1sQaP6TE.js';
2
+
3
+ /**
4
+ * Cookie domain / attribute policy for TKTChurch browser sessions.
5
+ *
6
+ * - `sso` — tiny opaque identity cookie on the parent domain (`.tktchurch.com`)
7
+ * - `app` — host-only product session (never parent Domain — avoids 431 bleed)
8
+ * - `transient` — host-only short-lived PKCE / OTP state
9
+ */
10
+ type CookieKind = "sso" | "app" | "transient";
11
+ interface CookiePolicyInput {
12
+ kind: CookieKind;
13
+ /** Request hostname without port (e.g. `developers.tktchurch.com`). */
14
+ hostname?: string;
15
+ maxAge?: number;
16
+ /**
17
+ * Force Secure. Defaults to true unless `allowInsecure` is set.
18
+ * Never derive Secure from client-controlled `X-Forwarded-Proto`.
19
+ */
20
+ secure?: boolean;
21
+ /** Local HTTP only — mirrors ALLOW_INSECURE_COOKIES. */
22
+ allowInsecure?: boolean;
23
+ /**
24
+ * Parent domain for `sso` cookies. Defaults to `tktchurch.com` when hostname
25
+ * ends with `.tktchurch.com`, else `tktchurch.net` for `.tktchurch.net`.
26
+ */
27
+ ssoParentDomain?: string;
28
+ path?: string;
29
+ sameSite?: "lax" | "strict" | "none";
30
+ }
31
+ /** Options compatible with h3 `setCookie` / the `cookie` package. */
32
+ interface SessionCookieOptions {
33
+ httpOnly: true;
34
+ secure: boolean;
35
+ sameSite: "lax" | "strict" | "none";
36
+ path: string;
37
+ maxAge?: number;
38
+ /** Only set for `kind: "sso"`. */
39
+ domain?: string;
40
+ }
41
+ declare const DEFAULT_SSO_COOKIE_NAME = "tkt_sid";
42
+ declare const DEFAULT_SSO_MAX_AGE_SECONDS: number;
43
+ declare const DEFAULT_TRANSIENT_MAX_AGE_SECONDS: number;
44
+ declare const DEFAULT_APP_MAX_AGE_SECONDS: number;
45
+ /** Parent registrable domain for SSO, or undefined when not on a TKT host. */
46
+ declare function resolveSsoParentDomain(hostname: string | undefined, override?: string): string | undefined;
47
+ /**
48
+ * Build Set-Cookie attribute options for a session cookie kind.
49
+ * `app` and `transient` are always host-only (no `domain`).
50
+ */
51
+ declare function cookieOptions(input: CookiePolicyInput): SessionCookieOptions;
52
+ /** Serialize options into a `Set-Cookie` attribute suffix (no name=value). */
53
+ declare function formatCookieAttributes(options: SessionCookieOptions): string;
54
+ /** Full `Set-Cookie` header value. */
55
+ declare function serializeSetCookie(name: string, value: string, options: SessionCookieOptions): string;
56
+ /**
57
+ * Emit Max-Age=0 Set-Cookie headers that clear legacy parent-domain app cookies
58
+ * (the bleed that causes Deno 431 on microsites).
59
+ */
60
+ declare function expireLegacyParentDomainCookies(names: string[], input?: {
61
+ hostname?: string;
62
+ allowInsecure?: boolean;
63
+ parentDomains?: string[];
64
+ }): string[];
65
+ /** h3-compatible options for clearing a cookie (same domain/path as set). */
66
+ declare function clearCookieOptions(kind: CookieKind, input?: Omit<CookiePolicyInput, "kind" | "maxAge">): SessionCookieOptions;
67
+
68
+ /**
69
+ * AES-256-GCM seal/unseal for session cookies (Web Crypto — Node 18+, Deno, edge).
70
+ *
71
+ * Wire format matches existing Nuxt apps: `iv.tag.ciphertext` (each base64url).
72
+ */
73
+ /** Encrypt a UTF-8 string into `iv.tag.ciphertext` base64url parts. */
74
+ declare function sealString(secret: string, plaintext: string): Promise<string>;
75
+ /** Decrypt a `iv.tag.ciphertext` sealed string. */
76
+ declare function unsealString(secret: string, sealed: string): Promise<string>;
77
+ /** JSON seal helper. */
78
+ declare function sealJson<T>(secret: string, value: T): Promise<string>;
79
+ /** JSON unseal helper. */
80
+ declare function unsealJson<T>(secret: string, sealed: string): Promise<T>;
81
+
82
+ /**
83
+ * Progressive compaction so sealed session cookies stay under browser limits.
84
+ */
85
+ declare const DEFAULT_MAX_SESSION_COOKIE_VALUE_LENGTH = 3800;
86
+ type CompactRoleMode = "all" | "identity" | "none";
87
+ interface CompactableUser {
88
+ id?: string;
89
+ sub?: string;
90
+ organizationId?: string | null;
91
+ email?: string | null;
92
+ username?: string | null;
93
+ firstName?: string | null;
94
+ lastName?: string | null;
95
+ phoneNumber?: string | null;
96
+ emailVerified?: boolean;
97
+ phoneNumberVerified?: boolean;
98
+ isActive?: boolean;
99
+ isVerified?: boolean;
100
+ mfaEnabled?: boolean;
101
+ picture?: string | null;
102
+ permissions?: string[];
103
+ roles?: Array<{
104
+ id?: string;
105
+ organizationId?: string | null;
106
+ name?: string | null;
107
+ slug?: string | null;
108
+ description?: string | null;
109
+ isSystem?: boolean;
110
+ permissions?: unknown[];
111
+ [key: string]: unknown;
112
+ }>;
113
+ [key: string]: unknown;
114
+ }
115
+ interface CompactableSession {
116
+ accessToken?: string;
117
+ refreshToken?: string;
118
+ idToken?: string;
119
+ expiresAt?: number;
120
+ scope?: string;
121
+ rememberMe?: boolean;
122
+ user?: CompactableUser;
123
+ [key: string]: unknown;
124
+ }
125
+ declare function slimUserForCookie(user: CompactableUser, options?: {
126
+ includePicture?: boolean;
127
+ roles?: CompactRoleMode;
128
+ }): CompactableUser;
129
+ /**
130
+ * Pick the smallest session variant that fits `maxLength` when JSON-stringified
131
+ * (caller should measure sealed length; this uses JSON length as a stand-in when
132
+ * `measure` is omitted).
133
+ */
134
+ declare function compactSession<T extends CompactableSession>(session: T, options?: {
135
+ maxLength?: number;
136
+ /** Return true when the candidate fits (e.g. sealed length). */
137
+ measure?: (candidate: T) => boolean | Promise<boolean>;
138
+ }): T | Promise<T>;
139
+ /** Sync compact using sealed-length measurement. */
140
+ declare function compactSessionForSeal<T extends CompactableSession>(secret: string, session: T, maxLength?: number): Promise<T>;
141
+
142
+ /**
143
+ * Opaque SSO session id (`tkt_sid`) + pluggable store.
144
+ */
145
+
146
+ interface SsoSessionRecord {
147
+ /** Subject / user id. */
148
+ userId: string;
149
+ /** Optional refresh-token handle or hash (never required for presence checks). */
150
+ refreshHandle?: string;
151
+ createdAt: number;
152
+ expiresAt: number;
153
+ rememberMe?: boolean;
154
+ }
155
+ interface SidStore {
156
+ get(sid: string): Promise<SsoSessionRecord | null>;
157
+ set(sid: string, record: SsoSessionRecord, ttlSeconds: number): Promise<void>;
158
+ delete(sid: string): Promise<void>;
159
+ }
160
+ /** In-memory store (tests / single-process only). */
161
+ declare class MemorySidStore implements SidStore {
162
+ private readonly map;
163
+ get(sid: string): Promise<SsoSessionRecord | null>;
164
+ set(sid: string, record: SsoSessionRecord, ttlSeconds: number): Promise<void>;
165
+ delete(sid: string): Promise<void>;
166
+ }
167
+ /**
168
+ * Redis-compatible store. Pass any client with get/set/del
169
+ * (node-redis, ioredis, Upstash REST wrapper, etc.).
170
+ */
171
+ interface RedisLike {
172
+ get(key: string): Promise<string | null>;
173
+ set(key: string, value: string, options?: {
174
+ ex?: number;
175
+ }): Promise<unknown>;
176
+ del(key: string): Promise<unknown>;
177
+ }
178
+ declare class RedisSidStore implements SidStore {
179
+ private readonly redis;
180
+ private readonly keyPrefix;
181
+ constructor(redis: RedisLike, keyPrefix?: string);
182
+ private key;
183
+ get(sid: string): Promise<SsoSessionRecord | null>;
184
+ set(sid: string, record: SsoSessionRecord, ttlSeconds: number): Promise<void>;
185
+ delete(sid: string): Promise<void>;
186
+ }
187
+ /**
188
+ * Cookie-embedded SSO record when no Redis is available (Accounts on Vercel).
189
+ * The cookie value is the sealed record itself (still tiny — no JWTs).
190
+ * `sid` returned to callers is a random id used only as a local handle; the
191
+ * sealed payload is what browsers store as `tkt_sid`.
192
+ */
193
+ interface SealedSidCookie {
194
+ /** Value to put in the `tkt_sid` cookie (sealed JSON). */
195
+ cookieValue: string;
196
+ record: SsoSessionRecord;
197
+ }
198
+ declare function mintSealedSsoCookieValue(secret: string, record: Omit<SsoSessionRecord, "createdAt"> & {
199
+ createdAt?: number;
200
+ }): Promise<SealedSidCookie>;
201
+ declare function readSealedSsoCookieValue(secret: string, cookieValue: string): Promise<SsoSessionRecord | null>;
202
+ declare function createOpaqueSid(bytes?: number): string;
203
+ declare function mintOpaqueSsoSession(store: SidStore, record: Omit<SsoSessionRecord, "createdAt" | "expiresAt"> & {
204
+ ttlSeconds?: number;
205
+ expiresAt?: number;
206
+ }): Promise<{
207
+ sid: string;
208
+ record: SsoSessionRecord;
209
+ }>;
210
+ declare function revokeSsoSession(store: SidStore, sid: string): Promise<void>;
211
+ declare function ssoSetCookieHeader(sidOrSealedValue: string, input?: {
212
+ hostname?: string;
213
+ maxAge?: number;
214
+ allowInsecure?: boolean;
215
+ cookieName?: string;
216
+ }): string;
217
+ declare function ssoClearCookieHeader(input?: {
218
+ hostname?: string;
219
+ allowInsecure?: boolean;
220
+ cookieName?: string;
221
+ }): string;
222
+ declare function ssoCookieOptions(input?: {
223
+ hostname?: string;
224
+ maxAge?: number;
225
+ allowInsecure?: boolean;
226
+ }): SessionCookieOptions;
227
+ /** Read a named cookie from a Cookie header. */
228
+ declare function readCookieHeader(cookieHeader: string | null | undefined, name: string): string | null;
229
+
230
+ /**
231
+ * High-level session cookie helpers shared by Nuxt (h3) and Deno apps.
232
+ */
233
+
234
+ interface SessionCookieConfig {
235
+ secret: string;
236
+ /** Product session cookie name (e.g. `dev_auth_session`). */
237
+ cookieName: string;
238
+ /** Default kind for the main session cookie. */
239
+ kind?: Exclude<CookieKind, "sso">;
240
+ maxValueLength?: number;
241
+ allowInsecure?: boolean;
242
+ /** Cookie names previously set with Domain=.tktchurch.com to expire. */
243
+ legacyParentDomainNames?: string[];
244
+ }
245
+ interface SetSessionInput {
246
+ hostname?: string;
247
+ maxAge?: number;
248
+ kind?: Exclude<CookieKind, "sso">;
249
+ }
250
+ /**
251
+ * Framework-agnostic session cookie controller.
252
+ * Use `serialize*` for Deno `Headers.append("set-cookie", …)` and
253
+ * `options*` with h3 `setCookie` / `deleteCookie`.
254
+ */
255
+ declare function createSessionCookies(config: SessionCookieConfig): {
256
+ cookieName: string;
257
+ sealSessionValue: <T extends CompactableSession>(session: T) => Promise<string>;
258
+ readSessionValue: <T>(raw: string | null | undefined) => Promise<T | null>;
259
+ optionsFor: (input?: SetSessionInput) => SessionCookieOptions;
260
+ clearOptionsFor: (input?: SetSessionInput) => SessionCookieOptions;
261
+ serializeSessionSetCookie: <T extends CompactableSession>(session: T, input?: SetSessionInput) => Promise<string>;
262
+ serializeSessionClearCookie: (input?: SetSessionInput) => string;
263
+ serializeLegacyExpiry: (hostname?: string) => string[];
264
+ sealTransient: (value: unknown) => Promise<string>;
265
+ unsealTransient: <T>(raw: string | null | undefined) => Promise<T | null>;
266
+ transientOptions: (hostname?: string, maxAge?: number) => SessionCookieOptions;
267
+ };
268
+ type SessionCookies = ReturnType<typeof createSessionCookies>;
269
+
270
+ /**
271
+ * Silent / prompt=none authorization helpers for cross-app SSO.
272
+ */
273
+
274
+ interface SilentAuthorizeOptions extends Omit<AuthorizationUrlOptions, "prompt"> {
275
+ /** When true (default), sets `prompt=none`. */
276
+ silent?: boolean;
277
+ }
278
+ /**
279
+ * Start an authorization-code + PKCE request intended for SSO resume.
280
+ * Persist `state` / `nonce` / `codeVerifier` in a **host-only transient** cookie.
281
+ */
282
+ declare function startSilentAuthorize(client: AuthClient, options: SilentAuthorizeOptions): Promise<AuthorizationRequest>;
283
+ /**
284
+ * True when an SSO identity cookie is present (opaque sid or sealed record).
285
+ * Does not validate the store — callers should resolve via SidStore / unseal.
286
+ */
287
+ declare function hasSsoCookieHint(cookieHeader: string | null | undefined, cookieName?: string): boolean;
288
+
289
+ export { type CompactRoleMode, type CompactableSession, type CompactableUser, type CookieKind, type CookiePolicyInput, DEFAULT_APP_MAX_AGE_SECONDS, DEFAULT_MAX_SESSION_COOKIE_VALUE_LENGTH, DEFAULT_SSO_COOKIE_NAME, DEFAULT_SSO_MAX_AGE_SECONDS, DEFAULT_TRANSIENT_MAX_AGE_SECONDS, MemorySidStore, type RedisLike, RedisSidStore, type SealedSidCookie, type SessionCookieConfig, type SessionCookieOptions, type SessionCookies, type SetSessionInput, type SidStore, type SilentAuthorizeOptions, type SsoSessionRecord, clearCookieOptions, compactSession, compactSessionForSeal, cookieOptions, createOpaqueSid, createSessionCookies, expireLegacyParentDomainCookies, formatCookieAttributes, hasSsoCookieHint, mintOpaqueSsoSession, mintSealedSsoCookieValue, readCookieHeader, readSealedSsoCookieValue, resolveSsoParentDomain, revokeSsoSession, sealJson, sealString, serializeSetCookie, slimUserForCookie, ssoClearCookieHeader, ssoCookieOptions, ssoSetCookieHeader, startSilentAuthorize, unsealJson, unsealString };
package/dist/server.js ADDED
@@ -0,0 +1 @@
1
+ var X=Object.defineProperty;var L=(e,t)=>()=>(e&&(t=e(e=0)),t);var B=(e,t)=>{for(var n in t)X(e,n,{get:t[n],enumerable:!0})};var l,_=L(()=>{"use strict";l=class extends Error{code;status;details;constructor(t,n,r){super(n),this.name="AuthError",this.code=t,this.status=r?.status,this.details=r?.details}}});var K={};B(K,{sealJson:()=>g,sealString:()=>v,unsealJson:()=>S,unsealString:()=>N});function I(){let e=globalThis.crypto;if(!e?.subtle||!e.getRandomValues)throw new l("server_error","Web Crypto API is unavailable; session seal requires globalThis.crypto.subtle.");return e}function O(e){let t="";for(let n of e)t+=String.fromCharCode(n);if(typeof btoa!="function")throw new l("server_error","base64UrlEncode requires globalThis.btoa.");return btoa(t).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/g,"")}function P(e){let t=e.replace(/-/g,"+").replace(/_/g,"/"),n=t.length%4===0?"":"=".repeat(4-t.length%4);if(typeof atob!="function")throw new l("server_error","base64UrlDecode requires globalThis.atob.");let r=atob(t+n),s=new Uint8Array(r.length);for(let o=0;o<r.length;o++)s[o]=r.charCodeAt(o);return s}async function z(e){let t=F.get(e);return t||(t=(async()=>{let n=I(),r=await n.subtle.digest("SHA-256",new TextEncoder().encode(e));return n.subtle.importKey("raw",r,{name:"AES-GCM"},!1,["encrypt","decrypt"])})(),F.set(e,t),t)}async function v(e,t){if(!e||e.length<16)throw new l("invalid_request","Session secret must be at least 16 characters.");let n=I(),r=await z(e),s=n.getRandomValues(new Uint8Array(V)),o=new Uint8Array(await n.subtle.encrypt({name:"AES-GCM",iv:s},r,new TextEncoder().encode(t)));if(o.length<b)throw new l("server_error","AES-GCM encrypt produced empty output.");let c=o.slice(0,o.length-b),u=o.slice(o.length-b);return[O(s),O(u),O(c)].join(".")}async function N(e,t){let n=t.split(".");if(n.length!==3||!n[0]||!n[1]||!n[2])throw new l("invalid_token","Invalid sealed session format.");let r=P(n[0]),s=P(n[1]),o=P(n[2]);if(r.length!==V||s.length!==b)throw new l("invalid_token","Invalid sealed session parts.");let c=new Uint8Array(o.length+s.length);c.set(o),c.set(s,o.length);let u=I(),C=await z(e);try{let a=await u.subtle.decrypt({name:"AES-GCM",iv:r},C,c);return new TextDecoder().decode(a)}catch{throw new l("invalid_token","Failed to decrypt session.")}}async function g(e,t){return v(e,JSON.stringify(t))}async function S(e,t){return JSON.parse(await N(e,t))}var V,b,F,k=L(()=>{"use strict";_();V=12,b=16;F=new Map});var A="tkt_sid",y=2592e3,W=600,j=2592e3;function E(e,t){if(t)return t;let n=((e||"").split(":")[0]||"").toLowerCase();if(n){if(n==="tktchurch.com"||n.endsWith(".tktchurch.com"))return"tktchurch.com";if(n==="tktchurch.net"||n.endsWith(".tktchurch.net"))return"tktchurch.net"}}function d(e){let t=e.allowInsecure===!0,n=e.secure??!t,r=e.sameSite??"lax",s=e.path??"/",o={httpOnly:!0,secure:n,sameSite:r,path:s};if(typeof e.maxAge=="number"?o.maxAge=e.maxAge:e.kind==="transient"?o.maxAge=600:e.kind==="sso"&&(o.maxAge=2592e3),e.kind==="sso"){let c=E(e.hostname,e.ssoParentDomain);c&&(o.domain=c)}return o}function q(e){let t=[`Path=${e.path}`,"HttpOnly"];return e.secure&&t.push("Secure"),t.push(`SameSite=${e.sameSite==="none"?"None":e.sameSite==="strict"?"Strict":"Lax"}`),typeof e.maxAge=="number"&&t.push(`Max-Age=${e.maxAge}`),e.domain&&t.push(`Domain=${e.domain}`),t.join("; ")}function m(e,t,n){return`${e}=${t}; ${q(n)}`}function T(e,t={}){let n=t.parentDomains??[],r=E(t.hostname);r&&!n.includes(r)&&n.push(r),n.length===0&&n.push("tktchurch.com","tktchurch.net");let s=t.allowInsecure===!0,o=[];for(let c of e)for(let u of n)o.push(m(c,"",{httpOnly:!0,secure:!s,sameSite:"lax",path:"/",maxAge:0,domain:u}));return o}function x(e,t={}){return d({...t,kind:e,maxAge:0})}k();var U=3800;function Y(e){let t=e||[];return t.includes("*:*")?["*:*"]:t}function Q(e){if(typeof e!="string")return null;let t=e.trim();return!t||t.startsWith("data:")||t.length>512?null:t}function Z(e,t){let n=(e||[]).map(r=>({...r,description:null,permissions:[]}));return t==="none"?[]:(t==="identity"&&(n=n.filter(r=>r.slug==="admin"||r.slug==="superadmin"||r.slug==="super_admin").slice(0,4)),n)}function f(e,t={}){let n=t.includePicture!==!1,r=t.roles||"all";return{...e,phoneNumber:e.phoneNumber??null,roles:Z(e.roles,r),permissions:Y(e.permissions),picture:n?Q(e.picture):null}}function $(e,t={}){let n=t.maxLength??3800,r=t.measure??(a=>JSON.stringify(a).length<=n),s=e.user;if(!s){let a={...e,idToken:void 0},h=r(a);return h instanceof Promise?h.then(w=>a):a}let o={...e,idToken:void 0},c=[e,o,{...o,user:f(s,{roles:"all"})},{...o,user:f(s,{roles:"identity"})},{...o,user:f(s,{roles:"none",includePicture:!0})},{...o,user:f(s,{roles:"none",includePicture:!1})}],u={...e,idToken:void 0,accessToken:e.accessToken,refreshToken:e.refreshToken,user:f(s,{roles:"none",includePicture:!1})};if(c.every(a=>typeof r(a)=="boolean")){for(let a of c)if(r(a))return a;return u}return(async()=>{for(let a of c)if(await r(a))return a;return u})()}async function D(e,t,n=3800){let{sealJson:r}=await Promise.resolve().then(()=>(k(),K)),s=$(t,{maxLength:n,measure:async o=>(await r(e,o)).length<=n});return s instanceof Promise,s}_();_();function ee(){let e=globalThis.crypto;if(!e?.getRandomValues)throw new l("invalid_request","Web Crypto API is unavailable in this runtime. PKCE requires globalThis.crypto.");return e}function te(e){let t="";for(let r of e)t+=String.fromCharCode(r);if(typeof btoa!="function")throw new l("server_error","base64UrlEncode requires globalThis.btoa (Web/Deno runtime).");return btoa(t).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/g,"")}function G(e=32){if(!Number.isInteger(e)||e<=0)throw new l("invalid_request","randomUrlSafeString length must be a positive integer.");let t=new Uint8Array(e);return ee().getRandomValues(t),te(t)}k();var M=class{map=new Map;async get(t){let n=this.map.get(t);return n?n.expiresAtMs<=Date.now()?(this.map.delete(t),null):n.record:null}async set(t,n,r){this.map.set(t,{record:n,expiresAtMs:Date.now()+Math.max(1,r)*1e3})}async delete(t){this.map.delete(t)}},R=class{constructor(t,n="tkt:sso:"){this.redis=t;this.keyPrefix=n}key(t){return`${this.keyPrefix}${t}`}async get(t){let n=await this.redis.get(this.key(t));if(!n)return null;try{let r=JSON.parse(n);return r.expiresAt<=Date.now()?(await this.delete(t),null):r}catch{return null}}async set(t,n,r){await this.redis.set(this.key(t),JSON.stringify(n),{ex:Math.max(1,r)})}async delete(t){await this.redis.del(this.key(t))}};async function ne(e,t){let n={...t,createdAt:t.createdAt??Date.now()};return{cookieValue:await g(e,n),record:n}}async function re(e,t){try{let n=await S(e,t);return!n?.userId||n.expiresAt<=Date.now()?null:n}catch{return null}}function H(e=32){return G(e)}async function oe(e,t){let n=t.ttlSeconds??2592e3,r=H(),s={userId:t.userId,refreshHandle:t.refreshHandle,rememberMe:t.rememberMe,createdAt:Date.now(),expiresAt:t.expiresAt??Date.now()+n*1e3};return await e.set(r,s,n),{sid:r,record:s}}async function se(e,t){await e.delete(t)}function ie(e,t={}){let n=t.cookieName??A,r=d({kind:"sso",hostname:t.hostname,maxAge:t.maxAge??2592e3,allowInsecure:t.allowInsecure});if(!r.domain)throw new l("invalid_request","SSO cookie requires a tktchurch.com / tktchurch.net hostname.");return m(n,e,r)}function ae(e={}){let t=e.cookieName??A,n=d({kind:"sso",hostname:e.hostname,maxAge:0,allowInsecure:e.allowInsecure});return m(t,"",n)}function ce(e={}){return d({kind:"sso",hostname:e.hostname,maxAge:e.maxAge??2592e3,allowInsecure:e.allowInsecure})}function le(e,t){if(!e)return null;let n=e.match(new RegExp(`(?:^|;\\s*)${t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}=([^;]*)`));return n?.[1]?decodeURIComponent(n[1]):null}k();function ue(e){let t=e.kind??"app",n=e.maxValueLength??3800,r=e.allowInsecure===!0;async function s(i){let p=await D(e.secret,i,n);return g(e.secret,p)}async function o(i){if(!i)return null;try{return await S(e.secret,i)}catch{return null}}function c(i={}){return d({kind:i.kind??t,hostname:i.hostname,maxAge:i.maxAge,allowInsecure:r})}async function u(i,p={}){let J=await s(i);return m(e.cookieName,J,c(p))}function C(i={}){return m(e.cookieName,"",x(i.kind??t,{hostname:i.hostname,allowInsecure:r}))}function a(i){let p=e.legacyParentDomainNames??[e.cookieName];return T(p,{hostname:i,allowInsecure:r})}async function h(i){return g(e.secret,i)}async function w(i){return o(i)}return{cookieName:e.cookieName,sealSessionValue:s,readSessionValue:o,optionsFor:c,clearOptionsFor:(i={})=>x(i.kind??t,{hostname:i.hostname,allowInsecure:r}),serializeSessionSetCookie:u,serializeSessionClearCookie:C,serializeLegacyExpiry:a,sealTransient:h,unsealTransient:w,transientOptions:(i,p)=>d({kind:"transient",hostname:i,maxAge:p,allowInsecure:r})}}async function de(e,t){let{silent:n=!0,...r}=t;return e.authorize.createRequest({...r,prompt:n?"none":void 0})}function me(e,t="tkt_sid"){if(!e)return!1;let n=t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");return new RegExp(`(?:^|;\\s*)${n}=([^;]+)`).test(e)}export{j as DEFAULT_APP_MAX_AGE_SECONDS,U as DEFAULT_MAX_SESSION_COOKIE_VALUE_LENGTH,A as DEFAULT_SSO_COOKIE_NAME,y as DEFAULT_SSO_MAX_AGE_SECONDS,W as DEFAULT_TRANSIENT_MAX_AGE_SECONDS,M as MemorySidStore,R as RedisSidStore,x as clearCookieOptions,$ as compactSession,D as compactSessionForSeal,d as cookieOptions,H as createOpaqueSid,ue as createSessionCookies,T as expireLegacyParentDomainCookies,q as formatCookieAttributes,me as hasSsoCookieHint,oe as mintOpaqueSsoSession,ne as mintSealedSsoCookieValue,le as readCookieHeader,re as readSealedSsoCookieValue,E as resolveSsoParentDomain,se as revokeSsoSession,g as sealJson,v as sealString,m as serializeSetCookie,f as slimUserForCookie,ae as ssoClearCookieHeader,ce as ssoCookieOptions,ie as ssoSetCookieHeader,de as startSilentAuthorize,S as unsealJson,N as unsealString};
@@ -1 +1,12 @@
1
- export { a8 as createMemoryTokenStorage } from '../memory-DCHtjktX.cjs';
1
+ import { a3 as TokenStorage } from '../types-1sQaP6TE.cjs';
2
+
3
+ /**
4
+ * Creates in-memory token storage suitable for Node, edge, and browser runtimes.
5
+ *
6
+ * Tokens are not encrypted and do not survive process restarts. This is the
7
+ * default and the recommended choice for server-side clients (SSR routes,
8
+ * workers) where persistence belongs in HttpOnly cookies or a server session.
9
+ */
10
+ declare function createMemoryTokenStorage(): TokenStorage;
11
+
12
+ export { createMemoryTokenStorage };
@@ -1 +1,12 @@
1
- export { a8 as createMemoryTokenStorage } from '../memory-DCHtjktX.js';
1
+ import { a3 as TokenStorage } from '../types-1sQaP6TE.js';
2
+
3
+ /**
4
+ * Creates in-memory token storage suitable for Node, edge, and browser runtimes.
5
+ *
6
+ * Tokens are not encrypted and do not survive process restarts. This is the
7
+ * default and the recommended choice for server-side clients (SSR routes,
8
+ * workers) where persistence belongs in HttpOnly cookies or a server session.
9
+ */
10
+ declare function createMemoryTokenStorage(): TokenStorage;
11
+
12
+ export { createMemoryTokenStorage };
@@ -903,6 +903,10 @@ interface AuthorizationUrlOptions {
903
903
  codeChallengeMethod?: "S256" | "plain";
904
904
  /** OIDC `prompt` parameter (e.g. `login`, `none`, `consent`). */
905
905
  prompt?: string;
906
+ /** OIDC maximum authentication age in seconds. Use `0` for a fresh login. */
907
+ maxAge?: number;
908
+ /** Ordered OIDC Authentication Context Class References. */
909
+ acrValues?: string[];
906
910
  /** OIDC `login_hint` to prefill the identifier. */
907
911
  loginHint?: string;
908
912
  /** OAuth `response_type`. Defaults to `code`. */
@@ -1204,6 +1208,24 @@ interface UserProfile {
1204
1208
  mfaEnabled?: boolean;
1205
1209
  [key: string]: JsonValue | undefined;
1206
1210
  }
1211
+ /** Lifecycle state for one private avatar version. */
1212
+ type AvatarAssetState = "created" | "processing" | "active" | "deleted";
1213
+ /**
1214
+ * Private avatar-history metadata.
1215
+ *
1216
+ * The OAuth API intentionally does not expose source URLs or managed object
1217
+ * keys. Use `UserProfile.picture` for the active compatibility image.
1218
+ */
1219
+ interface AvatarAsset {
1220
+ id: string;
1221
+ state: AvatarAssetState;
1222
+ isActive: boolean;
1223
+ isManaged: boolean;
1224
+ contentType?: string;
1225
+ byteCount?: number;
1226
+ createdAt?: string;
1227
+ deletedAt?: string;
1228
+ }
1207
1229
  /** Starts primary-email verification without changing the current email. */
1208
1230
  interface StartEmailVerificationRequest {
1209
1231
  email: string;
@@ -1316,6 +1338,12 @@ interface UserEndpoints {
1316
1338
  newPassword: string;
1317
1339
  }): Promise<void>;
1318
1340
  uploadAvatar(file: Blob | Buffer, filename?: string): Promise<UserProfile>;
1341
+ avatarAssets: {
1342
+ list(): Promise<AvatarAsset[]>;
1343
+ select(assetId: string): Promise<AvatarAsset>;
1344
+ delete(assetId: string): Promise<void>;
1345
+ };
1346
+ /** Deselects the current avatar without deleting retained history. */
1319
1347
  deleteAvatar(): Promise<UserProfile>;
1320
1348
  verifyPhone(input: JsonObject): Promise<JsonObject>;
1321
1349
  verifyRecoveryEmail(input: JsonObject): Promise<JsonObject>;
@@ -1402,13 +1430,4 @@ interface ApiRequestOptions {
1402
1430
  token?: string;
1403
1431
  }
1404
1432
 
1405
- /**
1406
- * Creates in-memory token storage suitable for Node, edge, and browser runtimes.
1407
- *
1408
- * Tokens are not encrypted and do not survive process restarts. This is the
1409
- * default and the recommended choice for server-side clients (SSR routes,
1410
- * workers) where persistence belongs in HttpOnly cookies or a server session.
1411
- */
1412
- declare function createMemoryTokenStorage(): TokenStorage;
1413
-
1414
- export { type TokenExchangeRequest as $, type AuthClientConfig as A, type OidcDiscoveryDocument as B, type ConsumerAuthClient as C, type OidcEndpoints as D, type EmailVerificationResponse as E, type FlowEndpoints as F, type PageResponse as G, type HandleCallbackOptions as H, type InitAuthenticationRequest as I, type PasswordResetEndpoints as J, type PasswordTokenRequest as K, type PublicClientInfo as L, type MaintenanceStatus as M, type PushAuthorizationRequestOptions as N, type OAuthAuthorizationServerMetadata as O, type PageQuery as P, type PushedAuthorizationResult as Q, type RefreshTokenRequest as R, type RevocationResponse as S, type RevokeSessionRequest as T, type RevokeTokenRequest as U, type SessionDetail as V, type SessionEndpoints as W, type SessionListQuery as X, type SessionSummary as Y, type StartEmailVerificationRequest as Z, type TokenEndpoints as _, type AuthClient as a, type TokenIntrospectionResponse as a0, type TokenStorage as a1, type UpdateSessionRequest as a2, type UserEndpoints as a3, type UserInfoResponse as a4, type UserProfile as a5, type VerifyEmailVerificationRequest as a6, type WebAuthnEndpoints as a7, createMemoryTokenStorage as a8, type AuthTokens as b, type AuthorizationCodeTokenRequest as c, type AuthorizationConsentBody as d, type AuthorizationConsentResponse as e, type AuthorizationDetail as f, type AuthorizationProbeResult as g, type AuthorizationRequest as h, type AuthorizationUrlOptions as i, type AuthorizeEndpoints as j, type CallbackParams as k, type ClientCredentialsRequest as l, type ConsumerMaintenanceEndpoints as m, type ConsumerUserEndpoints as n, type ExecuteStepRequest as o, type FlowInitResponse as p, type FlowSessionStatus as q, type FlowStep as r, type FlowStepCompleteResult as s, type FlowStepInProgressResult as t, type FlowStepResult as u, type InitRegistrationRequest as v, type IntrospectTokenRequest as w, type MfaDevice as x, type MfaEndpoints as y, type OAuthMetaEndpoints as z };
1433
+ export type { StartEmailVerificationRequest as $, AuthClientConfig as A, MfaEndpoints as B, ConsumerAuthClient as C, OAuthMetaEndpoints as D, EmailVerificationResponse as E, FlowEndpoints as F, OidcDiscoveryDocument as G, HandleCallbackOptions as H, InitAuthenticationRequest as I, OidcEndpoints as J, PageResponse as K, PasswordResetEndpoints as L, MaintenanceStatus as M, PasswordTokenRequest as N, OAuthAuthorizationServerMetadata as O, PageQuery as P, PublicClientInfo as Q, PushAuthorizationRequestOptions as R, PushedAuthorizationResult as S, RefreshTokenRequest as T, RevocationResponse as U, RevokeSessionRequest as V, RevokeTokenRequest as W, SessionDetail as X, SessionEndpoints as Y, SessionListQuery as Z, SessionSummary as _, AuthClient as a, TokenEndpoints as a0, TokenExchangeRequest as a1, TokenIntrospectionResponse as a2, TokenStorage as a3, UpdateSessionRequest as a4, UserEndpoints as a5, UserInfoResponse as a6, UserProfile as a7, VerifyEmailVerificationRequest as a8, WebAuthnEndpoints as a9, AuthTokens as b, AuthorizationCodeTokenRequest as c, AuthorizationConsentBody as d, AuthorizationConsentResponse as e, AuthorizationDetail as f, AuthorizationProbeResult as g, AuthorizationRequest as h, AuthorizationUrlOptions as i, AuthorizeEndpoints as j, AvatarAsset as k, AvatarAssetState as l, CallbackParams as m, ClientCredentialsRequest as n, ConsumerMaintenanceEndpoints as o, ConsumerUserEndpoints as p, ExecuteStepRequest as q, FlowInitResponse as r, FlowSessionStatus as s, FlowStep as t, FlowStepCompleteResult as u, FlowStepInProgressResult as v, FlowStepResult as w, InitRegistrationRequest as x, IntrospectTokenRequest as y, MfaDevice as z };
@@ -903,6 +903,10 @@ interface AuthorizationUrlOptions {
903
903
  codeChallengeMethod?: "S256" | "plain";
904
904
  /** OIDC `prompt` parameter (e.g. `login`, `none`, `consent`). */
905
905
  prompt?: string;
906
+ /** OIDC maximum authentication age in seconds. Use `0` for a fresh login. */
907
+ maxAge?: number;
908
+ /** Ordered OIDC Authentication Context Class References. */
909
+ acrValues?: string[];
906
910
  /** OIDC `login_hint` to prefill the identifier. */
907
911
  loginHint?: string;
908
912
  /** OAuth `response_type`. Defaults to `code`. */
@@ -1204,6 +1208,24 @@ interface UserProfile {
1204
1208
  mfaEnabled?: boolean;
1205
1209
  [key: string]: JsonValue | undefined;
1206
1210
  }
1211
+ /** Lifecycle state for one private avatar version. */
1212
+ type AvatarAssetState = "created" | "processing" | "active" | "deleted";
1213
+ /**
1214
+ * Private avatar-history metadata.
1215
+ *
1216
+ * The OAuth API intentionally does not expose source URLs or managed object
1217
+ * keys. Use `UserProfile.picture` for the active compatibility image.
1218
+ */
1219
+ interface AvatarAsset {
1220
+ id: string;
1221
+ state: AvatarAssetState;
1222
+ isActive: boolean;
1223
+ isManaged: boolean;
1224
+ contentType?: string;
1225
+ byteCount?: number;
1226
+ createdAt?: string;
1227
+ deletedAt?: string;
1228
+ }
1207
1229
  /** Starts primary-email verification without changing the current email. */
1208
1230
  interface StartEmailVerificationRequest {
1209
1231
  email: string;
@@ -1316,6 +1338,12 @@ interface UserEndpoints {
1316
1338
  newPassword: string;
1317
1339
  }): Promise<void>;
1318
1340
  uploadAvatar(file: Blob | Buffer, filename?: string): Promise<UserProfile>;
1341
+ avatarAssets: {
1342
+ list(): Promise<AvatarAsset[]>;
1343
+ select(assetId: string): Promise<AvatarAsset>;
1344
+ delete(assetId: string): Promise<void>;
1345
+ };
1346
+ /** Deselects the current avatar without deleting retained history. */
1319
1347
  deleteAvatar(): Promise<UserProfile>;
1320
1348
  verifyPhone(input: JsonObject): Promise<JsonObject>;
1321
1349
  verifyRecoveryEmail(input: JsonObject): Promise<JsonObject>;
@@ -1402,13 +1430,4 @@ interface ApiRequestOptions {
1402
1430
  token?: string;
1403
1431
  }
1404
1432
 
1405
- /**
1406
- * Creates in-memory token storage suitable for Node, edge, and browser runtimes.
1407
- *
1408
- * Tokens are not encrypted and do not survive process restarts. This is the
1409
- * default and the recommended choice for server-side clients (SSR routes,
1410
- * workers) where persistence belongs in HttpOnly cookies or a server session.
1411
- */
1412
- declare function createMemoryTokenStorage(): TokenStorage;
1413
-
1414
- export { type TokenExchangeRequest as $, type AuthClientConfig as A, type OidcDiscoveryDocument as B, type ConsumerAuthClient as C, type OidcEndpoints as D, type EmailVerificationResponse as E, type FlowEndpoints as F, type PageResponse as G, type HandleCallbackOptions as H, type InitAuthenticationRequest as I, type PasswordResetEndpoints as J, type PasswordTokenRequest as K, type PublicClientInfo as L, type MaintenanceStatus as M, type PushAuthorizationRequestOptions as N, type OAuthAuthorizationServerMetadata as O, type PageQuery as P, type PushedAuthorizationResult as Q, type RefreshTokenRequest as R, type RevocationResponse as S, type RevokeSessionRequest as T, type RevokeTokenRequest as U, type SessionDetail as V, type SessionEndpoints as W, type SessionListQuery as X, type SessionSummary as Y, type StartEmailVerificationRequest as Z, type TokenEndpoints as _, type AuthClient as a, type TokenIntrospectionResponse as a0, type TokenStorage as a1, type UpdateSessionRequest as a2, type UserEndpoints as a3, type UserInfoResponse as a4, type UserProfile as a5, type VerifyEmailVerificationRequest as a6, type WebAuthnEndpoints as a7, createMemoryTokenStorage as a8, type AuthTokens as b, type AuthorizationCodeTokenRequest as c, type AuthorizationConsentBody as d, type AuthorizationConsentResponse as e, type AuthorizationDetail as f, type AuthorizationProbeResult as g, type AuthorizationRequest as h, type AuthorizationUrlOptions as i, type AuthorizeEndpoints as j, type CallbackParams as k, type ClientCredentialsRequest as l, type ConsumerMaintenanceEndpoints as m, type ConsumerUserEndpoints as n, type ExecuteStepRequest as o, type FlowInitResponse as p, type FlowSessionStatus as q, type FlowStep as r, type FlowStepCompleteResult as s, type FlowStepInProgressResult as t, type FlowStepResult as u, type InitRegistrationRequest as v, type IntrospectTokenRequest as w, type MfaDevice as x, type MfaEndpoints as y, type OAuthMetaEndpoints as z };
1433
+ export type { StartEmailVerificationRequest as $, AuthClientConfig as A, MfaEndpoints as B, ConsumerAuthClient as C, OAuthMetaEndpoints as D, EmailVerificationResponse as E, FlowEndpoints as F, OidcDiscoveryDocument as G, HandleCallbackOptions as H, InitAuthenticationRequest as I, OidcEndpoints as J, PageResponse as K, PasswordResetEndpoints as L, MaintenanceStatus as M, PasswordTokenRequest as N, OAuthAuthorizationServerMetadata as O, PageQuery as P, PublicClientInfo as Q, PushAuthorizationRequestOptions as R, PushedAuthorizationResult as S, RefreshTokenRequest as T, RevocationResponse as U, RevokeSessionRequest as V, RevokeTokenRequest as W, SessionDetail as X, SessionEndpoints as Y, SessionListQuery as Z, SessionSummary as _, AuthClient as a, TokenEndpoints as a0, TokenExchangeRequest as a1, TokenIntrospectionResponse as a2, TokenStorage as a3, UpdateSessionRequest as a4, UserEndpoints as a5, UserInfoResponse as a6, UserProfile as a7, VerifyEmailVerificationRequest as a8, WebAuthnEndpoints as a9, AuthTokens as b, AuthorizationCodeTokenRequest as c, AuthorizationConsentBody as d, AuthorizationConsentResponse as e, AuthorizationDetail as f, AuthorizationProbeResult as g, AuthorizationRequest as h, AuthorizationUrlOptions as i, AuthorizeEndpoints as j, AvatarAsset as k, AvatarAssetState as l, CallbackParams as m, ClientCredentialsRequest as n, ConsumerMaintenanceEndpoints as o, ConsumerUserEndpoints as p, ExecuteStepRequest as q, FlowInitResponse as r, FlowSessionStatus as s, FlowStep as t, FlowStepCompleteResult as u, FlowStepInProgressResult as v, FlowStepResult as w, InitRegistrationRequest as x, IntrospectTokenRequest as y, MfaDevice as z };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tktchurch/auth",
3
- "version": "0.9.9",
3
+ "version": "0.11.0",
4
4
  "description": "Framework-agnostic auth SDK for TKTChurch OAuth/AuthFlow services",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -45,6 +45,11 @@
45
45
  "types": "./dist/nuxt/module.d.ts",
46
46
  "import": "./dist/nuxt/module.js",
47
47
  "require": "./dist/nuxt/module.cjs"
48
+ },
49
+ "./server": {
50
+ "types": "./dist/server.d.ts",
51
+ "import": "./dist/server.js",
52
+ "require": "./dist/server.cjs"
48
53
  }
49
54
  },
50
55
  "files": [