@cohostvip/cohost-auth 0.3.7 → 0.3.13
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.
- package/dist/index.d.mts +30 -1
- package/dist/index.d.ts +30 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -14,6 +14,12 @@ interface AuthConfig {
|
|
|
14
14
|
autoRefresh?: boolean;
|
|
15
15
|
/** Refresh tokens this many seconds before expiry (default: 300 = 5 minutes) */
|
|
16
16
|
refreshThreshold?: number;
|
|
17
|
+
/**
|
|
18
|
+
* Query string parameter name for token-based authentication (e.g., 'token' or 't').
|
|
19
|
+
* If set, the client will check for this param and attempt to authenticate with it.
|
|
20
|
+
* If not set, token param detection is disabled.
|
|
21
|
+
*/
|
|
22
|
+
tokenParam?: string;
|
|
17
23
|
}
|
|
18
24
|
/**
|
|
19
25
|
* User object returned from auth endpoints
|
|
@@ -132,6 +138,17 @@ interface TokenValidateResult {
|
|
|
132
138
|
exp?: number;
|
|
133
139
|
iat?: number;
|
|
134
140
|
}
|
|
141
|
+
/**
|
|
142
|
+
* Result from authenticating with a token
|
|
143
|
+
*/
|
|
144
|
+
interface TokenAuthResult {
|
|
145
|
+
/** Whether authentication succeeded */
|
|
146
|
+
success: boolean;
|
|
147
|
+
/** User if authentication succeeded */
|
|
148
|
+
user?: AuthUser;
|
|
149
|
+
/** Error message if authentication failed */
|
|
150
|
+
error?: string;
|
|
151
|
+
}
|
|
135
152
|
/**
|
|
136
153
|
* Error codes for auth operations
|
|
137
154
|
*/
|
|
@@ -200,6 +217,18 @@ declare class AuthClient {
|
|
|
200
217
|
* Use this when you handle authentication outside the standard OTP flow
|
|
201
218
|
*/
|
|
202
219
|
setAuthenticated(input: SetAuthenticatedInput): void;
|
|
220
|
+
/**
|
|
221
|
+
* Get the configured token param name (if any)
|
|
222
|
+
* Returns undefined if token param detection is disabled
|
|
223
|
+
*/
|
|
224
|
+
get tokenParamName(): string | undefined;
|
|
225
|
+
/**
|
|
226
|
+
* Authenticate using a token (e.g., from URL query param).
|
|
227
|
+
* Validates the token via API and sets auth state if valid.
|
|
228
|
+
* @param token - The token to authenticate with
|
|
229
|
+
* @returns Result indicating success/failure
|
|
230
|
+
*/
|
|
231
|
+
authenticateWithToken(token: string): Promise<TokenAuthResult>;
|
|
203
232
|
/**
|
|
204
233
|
* Get current access token, refreshing if needed
|
|
205
234
|
*/
|
|
@@ -346,4 +375,4 @@ declare const authErrors: {
|
|
|
346
375
|
*/
|
|
347
376
|
declare function createAuthClient(config: AuthConfig): AuthClient;
|
|
348
377
|
|
|
349
|
-
export { AuthApi, AuthClient, type AuthConfig, AuthError, type AuthErrorCode, type AuthResult, type AuthState, type AuthStateListener, type AuthUser, type OTPRequestInput, type OTPType, type OTPVerifyInput, type SetAuthenticatedInput, type TokenPair, type TokenRefreshInput, type TokenStorage, type TokenValidateInput, type TokenValidateResult, type Unsubscribe, authErrors, createAuthClient, createStorage };
|
|
378
|
+
export { AuthApi, AuthClient, type AuthConfig, AuthError, type AuthErrorCode, type AuthResult, type AuthState, type AuthStateListener, type AuthUser, type OTPRequestInput, type OTPType, type OTPVerifyInput, type SetAuthenticatedInput, type TokenAuthResult, type TokenPair, type TokenRefreshInput, type TokenStorage, type TokenValidateInput, type TokenValidateResult, type Unsubscribe, authErrors, createAuthClient, createStorage };
|
package/dist/index.d.ts
CHANGED
|
@@ -14,6 +14,12 @@ interface AuthConfig {
|
|
|
14
14
|
autoRefresh?: boolean;
|
|
15
15
|
/** Refresh tokens this many seconds before expiry (default: 300 = 5 minutes) */
|
|
16
16
|
refreshThreshold?: number;
|
|
17
|
+
/**
|
|
18
|
+
* Query string parameter name for token-based authentication (e.g., 'token' or 't').
|
|
19
|
+
* If set, the client will check for this param and attempt to authenticate with it.
|
|
20
|
+
* If not set, token param detection is disabled.
|
|
21
|
+
*/
|
|
22
|
+
tokenParam?: string;
|
|
17
23
|
}
|
|
18
24
|
/**
|
|
19
25
|
* User object returned from auth endpoints
|
|
@@ -132,6 +138,17 @@ interface TokenValidateResult {
|
|
|
132
138
|
exp?: number;
|
|
133
139
|
iat?: number;
|
|
134
140
|
}
|
|
141
|
+
/**
|
|
142
|
+
* Result from authenticating with a token
|
|
143
|
+
*/
|
|
144
|
+
interface TokenAuthResult {
|
|
145
|
+
/** Whether authentication succeeded */
|
|
146
|
+
success: boolean;
|
|
147
|
+
/** User if authentication succeeded */
|
|
148
|
+
user?: AuthUser;
|
|
149
|
+
/** Error message if authentication failed */
|
|
150
|
+
error?: string;
|
|
151
|
+
}
|
|
135
152
|
/**
|
|
136
153
|
* Error codes for auth operations
|
|
137
154
|
*/
|
|
@@ -200,6 +217,18 @@ declare class AuthClient {
|
|
|
200
217
|
* Use this when you handle authentication outside the standard OTP flow
|
|
201
218
|
*/
|
|
202
219
|
setAuthenticated(input: SetAuthenticatedInput): void;
|
|
220
|
+
/**
|
|
221
|
+
* Get the configured token param name (if any)
|
|
222
|
+
* Returns undefined if token param detection is disabled
|
|
223
|
+
*/
|
|
224
|
+
get tokenParamName(): string | undefined;
|
|
225
|
+
/**
|
|
226
|
+
* Authenticate using a token (e.g., from URL query param).
|
|
227
|
+
* Validates the token via API and sets auth state if valid.
|
|
228
|
+
* @param token - The token to authenticate with
|
|
229
|
+
* @returns Result indicating success/failure
|
|
230
|
+
*/
|
|
231
|
+
authenticateWithToken(token: string): Promise<TokenAuthResult>;
|
|
203
232
|
/**
|
|
204
233
|
* Get current access token, refreshing if needed
|
|
205
234
|
*/
|
|
@@ -346,4 +375,4 @@ declare const authErrors: {
|
|
|
346
375
|
*/
|
|
347
376
|
declare function createAuthClient(config: AuthConfig): AuthClient;
|
|
348
377
|
|
|
349
|
-
export { AuthApi, AuthClient, type AuthConfig, AuthError, type AuthErrorCode, type AuthResult, type AuthState, type AuthStateListener, type AuthUser, type OTPRequestInput, type OTPType, type OTPVerifyInput, type SetAuthenticatedInput, type TokenPair, type TokenRefreshInput, type TokenStorage, type TokenValidateInput, type TokenValidateResult, type Unsubscribe, authErrors, createAuthClient, createStorage };
|
|
378
|
+
export { AuthApi, AuthClient, type AuthConfig, AuthError, type AuthErrorCode, type AuthResult, type AuthState, type AuthStateListener, type AuthUser, type OTPRequestInput, type OTPType, type OTPVerifyInput, type SetAuthenticatedInput, type TokenAuthResult, type TokenPair, type TokenRefreshInput, type TokenStorage, type TokenValidateInput, type TokenValidateResult, type Unsubscribe, authErrors, createAuthClient, createStorage };
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var f=Object.defineProperty;var I=Object.getOwnPropertyDescriptor;var S=Object.getOwnPropertyNames;var v=Object.prototype.hasOwnProperty;var b=(r,e,t)=>e in r?f(r,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):r[e]=t;var w=(r,e)=>{for(var t in e)f(r,t,{get:e[t],enumerable:!0})},P=(r,e,t,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of S(e))!v.call(r,n)&&n!==t&&f(r,n,{get:()=>e[n],enumerable:!(s=I(e,n))||s.enumerable});return r};var x=r=>P(f({},"__esModule",{value:!0}),r);var i=(r,e,t)=>b(r,typeof e!="symbol"?e+"":e,t);var _={};w(_,{AuthApi:()=>T,AuthClient:()=>g,AuthError:()=>o,authErrors:()=>c,createAuthClient:()=>U,createStorage:()=>p});module.exports=x(_);var o=class r extends Error{constructor(t,s,n,a){super(t);i(this,"code");i(this,"statusCode");i(this,"originalError");this.name="AuthError",this.code=s,this.statusCode=n,this.originalError=a}static fromError(t,s="UNKNOWN_ERROR"){return t instanceof r?t:new r(t.message,s,void 0,t)}};var c={invalidEmail:()=>new o("Invalid email address","INVALID_EMAIL",400),invalidOTP:()=>new o("Invalid or incorrect OTP code","INVALID_OTP",400),otpExpired:()=>new o("OTP code has expired","OTP_EXPIRED",400),invalidToken:()=>new o("Invalid token","INVALID_TOKEN",401),tokenExpired:()=>new o("Token has expired","TOKEN_EXPIRED",401),networkError:(r="Network request failed")=>new o(r,"NETWORK_ERROR"),serverError:(r="Server error",e=500)=>new o(r,"SERVER_ERROR",e),unauthorized:()=>new o("Unauthorized","UNAUTHORIZED",401),notAuthenticated:()=>new o("User is not authenticated","NOT_AUTHENTICATED"),storageError:(r="Storage operation failed")=>new o(r,"STORAGE_ERROR"),unknown:(r="An unknown error occurred")=>new o(r,"UNKNOWN_ERROR")};function y(r,e){let t=r.status,s=r.statusText||"Request failed";if(typeof e=="object"&&e!==null){let a=e;s=a.error||a.message||s}else typeof e=="string"&&(s=e);let n;switch(t){case 400:n="INVALID_TOKEN";break;case 401:n="UNAUTHORIZED";break;case 403:n="UNAUTHORIZED";break;case 404:n="SERVER_ERROR";break;default:n=t>=500?"SERVER_ERROR":"UNKNOWN_ERROR"}return new o(s,n,t)}var u={ACCESS_TOKEN:"cohost_auth_access_token",REFRESH_TOKEN:"cohost_auth_refresh_token",TOKEN_EXPIRY:"cohost_auth_token_expiry",USER:"cohost_auth_user"};function O(){return typeof window<"u"&&typeof window.localStorage<"u"}var R=class{constructor(e){i(this,"storage");if(!O())throw new o("Web storage is not available in this environment","STORAGE_ERROR");this.storage=e==="localStorage"?window.localStorage:window.sessionStorage}getAccessToken(){try{return this.storage.getItem(u.ACCESS_TOKEN)}catch{return null}}setAccessToken(e){try{this.storage.setItem(u.ACCESS_TOKEN,e)}catch{throw new o("Failed to save access token","STORAGE_ERROR")}}getRefreshToken(){try{return this.storage.getItem(u.REFRESH_TOKEN)}catch{return null}}setRefreshToken(e){try{this.storage.setItem(u.REFRESH_TOKEN,e)}catch{throw new o("Failed to save refresh token","STORAGE_ERROR")}}getTokenExpiry(){try{let e=this.storage.getItem(u.TOKEN_EXPIRY);return e?parseInt(e,10):null}catch{return null}}setTokenExpiry(e){try{this.storage.setItem(u.TOKEN_EXPIRY,e.toString())}catch{throw new o("Failed to save token expiry","STORAGE_ERROR")}}getUser(){try{let e=this.storage.getItem(u.USER);return e?JSON.parse(e):null}catch{return null}}setUser(e){try{this.storage.setItem(u.USER,JSON.stringify(e))}catch{throw new o("Failed to save user","STORAGE_ERROR")}}clear(){try{this.storage.removeItem(u.ACCESS_TOKEN),this.storage.removeItem(u.REFRESH_TOKEN),this.storage.removeItem(u.TOKEN_EXPIRY),this.storage.removeItem(u.USER)}catch{}}},E=class{constructor(){i(this,"accessToken",null);i(this,"refreshToken",null);i(this,"tokenExpiry",null);i(this,"user",null)}getAccessToken(){return this.accessToken}setAccessToken(e){this.accessToken=e}getRefreshToken(){return this.refreshToken}setRefreshToken(e){this.refreshToken=e}getTokenExpiry(){return this.tokenExpiry}setTokenExpiry(e){this.tokenExpiry=e}getUser(){return this.user}setUser(e){this.user=e}clear(){this.accessToken=null,this.refreshToken=null,this.tokenExpiry=null,this.user=null}};function p(r){return r==="memory"||!O()?new E:new R(r)}var T=class{constructor(e,t=!1){i(this,"baseUrl");i(this,"debug");this.baseUrl=e.replace(/\/$/,""),this.debug=t}async request(e,t={}){let{method:s="GET",body:n,headers:a={},token:d}=t,k=`${this.baseUrl}${e}`,m={"Content-Type":"application/json",...a};d&&(m.Authorization=`Bearer ${d}`),this.debug&&(console.log(`[AuthClient] ${s} ${k}`),n&&console.log("[AuthClient] Body:",JSON.stringify(n)));let l;try{l=await fetch(k,{method:s,headers:m,body:n?JSON.stringify(n):void 0})}catch(A){throw c.networkError(A instanceof Error?A.message:"Network request failed")}let h=l.headers.get("content-type")?.includes("application/json")?await l.json():await l.text();if(this.debug&&console.log(`[AuthClient] Response (${l.status}):`,h),!l.ok)throw y(l,h);return typeof h=="object"&&h!==null&&h.status==="ok"&&"data"in h?h.data:h}async requestOTP(e){return this.request("/otp/request",{method:"POST",body:e})}async verifyOTP(e){return this.request("/otp/verify",{method:"POST",body:e})}async refreshToken(e){return this.request("/token/refresh",{method:"POST",body:e})}async validateToken(e){return this.request("/token/validate",{method:"POST",body:e})}async revokeToken(e){return this.request("/token/revoke",{method:"POST",token:e})}async getCurrentUser(e){return this.request("/me",{method:"GET",token:e})}};var N=300,g=class{constructor(e){i(this,"config");i(this,"storage");i(this,"api");i(this,"state");i(this,"listeners",new Set);i(this,"refreshTimer",null);i(this,"initialized",!1);this.config={apiUrl:e.apiUrl,channelId:e.channelId,storage:e.storage??"localStorage",debug:e.debug??!1,autoRefresh:e.autoRefresh??!0,refreshThreshold:e.refreshThreshold??N},this.storage=p(this.config.storage),this.api=new T(this.config.apiUrl,this.config.debug),this.state={isAuthenticated:!1,isLoading:!0,user:null,accessToken:null,error:null}}async initialize(){if(!this.initialized){this.debug("Initializing auth client");try{let e=this.storage.getAccessToken(),t=this.storage.getUser(),s=this.storage.getTokenExpiry();if(e&&t&&s){let n=Math.floor(Date.now()/1e3);if(s>n){this.updateState({isAuthenticated:!0,isLoading:!1,user:t,accessToken:e,error:null}),this.config.autoRefresh&&this.scheduleRefresh(s-n),this.initialized=!0;return}let a=this.storage.getRefreshToken();if(a){await this.performRefresh(a),this.initialized=!0;return}}this.storage.clear(),this.updateState({isAuthenticated:!1,isLoading:!1,user:null,accessToken:null,error:null})}catch(e){this.debug("Initialization error:",e),this.storage.clear(),this.updateState({isAuthenticated:!1,isLoading:!1,user:null,accessToken:null,error:o.fromError(e)})}this.initialized=!0}}getState(){return{...this.state}}onAuthStateChanged(e){return this.listeners.add(e),e(this.getState()),()=>{this.listeners.delete(e)}}get isAuthenticated(){return this.state.isAuthenticated}get currentUser(){return this.state.user}get accessToken(){return this.state.accessToken}async requestOTP(e,t="email"){this.debug("Requesting OTP for:",e,t);let s={contact:e,type:t,channelId:this.config.channelId};return(await this.api.requestOTP(s)).sent}async verifyOTP(e,t){this.debug("Verifying OTP for:",e);let s={contact:e,code:t,channelId:this.config.channelId},n=await this.api.verifyOTP(s);this.storage.setAccessToken(n.customToken),this.storage.setUser(n.user);let a=Math.floor(Date.now()/1e3)+10080*60;return this.storage.setTokenExpiry(a),this.updateState({isAuthenticated:!0,isLoading:!1,user:n.user,accessToken:n.customToken,error:null}),this.config.autoRefresh&&this.scheduleRefresh(10080*60),n.user}setAuthenticated(e){this.debug("Setting authenticated state for:",e.user.uid);let{accessToken:t,user:s,refreshToken:n,expiresIn:a=10080*60}=e;this.storage.setAccessToken(t),this.storage.setUser(s),n&&this.storage.setRefreshToken(n);let d=Math.floor(Date.now()/1e3)+a;this.storage.setTokenExpiry(d),this.updateState({isAuthenticated:!0,isLoading:!1,user:s,accessToken:t,error:null}),this.config.autoRefresh&&n&&this.scheduleRefresh(a)}async getToken(){if(!this.state.accessToken)return null;let e=this.storage.getTokenExpiry(),t=Math.floor(Date.now()/1e3);if(e&&e-t<this.config.refreshThreshold){let s=this.storage.getRefreshToken();s&&await this.performRefresh(s)}return this.state.accessToken}async refreshToken(){let e=this.storage.getRefreshToken();if(!e)throw c.notAuthenticated();await this.performRefresh(e)}async signOut(){if(this.debug("Signing out"),this.refreshTimer&&(clearTimeout(this.refreshTimer),this.refreshTimer=null),this.state.accessToken)try{await this.api.revokeToken(this.state.accessToken)}catch(e){this.debug("Revoke token error (ignored):",e)}this.storage.clear(),this.updateState({isAuthenticated:!1,isLoading:!1,user:null,accessToken:null,error:null})}async getCurrentUser(){if(!this.state.accessToken)return null;let e=await this.api.getCurrentUser(this.state.accessToken);return this.storage.setUser(e.user),this.updateState({...this.state,user:e.user}),e.user}updateState(e){this.state=e;for(let t of this.listeners)try{t(this.getState())}catch(s){this.debug("Listener error:",s)}}async performRefresh(e){this.debug("Refreshing token");try{let t=await this.api.refreshToken({refreshToken:e,channelId:this.config.channelId});this.storage.setAccessToken(t.accessToken),this.storage.setRefreshToken(t.refreshToken);let s=Math.floor(Date.now()/1e3)+t.expiresIn;this.storage.setTokenExpiry(s),this.updateState({...this.state,accessToken:t.accessToken,error:null}),this.config.autoRefresh&&this.scheduleRefresh(t.expiresIn)}catch(t){this.debug("Refresh failed:",t),this.storage.clear(),this.updateState({isAuthenticated:!1,isLoading:!1,user:null,accessToken:null,error:o.fromError(t,"TOKEN_EXPIRED")})}}scheduleRefresh(e){this.refreshTimer&&clearTimeout(this.refreshTimer);let t=Math.max(0,e-this.config.refreshThreshold)*1e3;this.debug(`Scheduling refresh in ${t/1e3}s`),this.refreshTimer=setTimeout(()=>{let s=this.storage.getRefreshToken();s&&this.performRefresh(s)},t)}debug(...e){this.config.debug&&console.log("[AuthClient]",...e)}};function U(r){return new g(r)}0&&(module.exports={AuthApi,AuthClient,AuthError,authErrors,createAuthClient,createStorage});
|
|
1
|
+
"use strict";var f=Object.defineProperty;var I=Object.getOwnPropertyDescriptor;var S=Object.getOwnPropertyNames;var v=Object.prototype.hasOwnProperty;var b=(s,e,t)=>e in s?f(s,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):s[e]=t;var P=(s,e)=>{for(var t in e)f(s,t,{get:e[t],enumerable:!0})},w=(s,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of S(e))!v.call(s,n)&&n!==t&&f(s,n,{get:()=>e[n],enumerable:!(r=I(e,n))||r.enumerable});return s};var x=s=>w(f({},"__esModule",{value:!0}),s);var i=(s,e,t)=>b(s,typeof e!="symbol"?e+"":e,t);var _={};P(_,{AuthApi:()=>g,AuthClient:()=>T,AuthError:()=>o,authErrors:()=>l,createAuthClient:()=>U,createStorage:()=>p});module.exports=x(_);var o=class s extends Error{constructor(t,r,n,a){super(t);i(this,"code");i(this,"statusCode");i(this,"originalError");this.name="AuthError",this.code=r,this.statusCode=n,this.originalError=a}static fromError(t,r="UNKNOWN_ERROR"){return t instanceof s?t:new s(t.message,r,void 0,t)}};var l={invalidEmail:()=>new o("Invalid email address","INVALID_EMAIL",400),invalidOTP:()=>new o("Invalid or incorrect OTP code","INVALID_OTP",400),otpExpired:()=>new o("OTP code has expired","OTP_EXPIRED",400),invalidToken:()=>new o("Invalid token","INVALID_TOKEN",401),tokenExpired:()=>new o("Token has expired","TOKEN_EXPIRED",401),networkError:(s="Network request failed")=>new o(s,"NETWORK_ERROR"),serverError:(s="Server error",e=500)=>new o(s,"SERVER_ERROR",e),unauthorized:()=>new o("Unauthorized","UNAUTHORIZED",401),notAuthenticated:()=>new o("User is not authenticated","NOT_AUTHENTICATED"),storageError:(s="Storage operation failed")=>new o(s,"STORAGE_ERROR"),unknown:(s="An unknown error occurred")=>new o(s,"UNKNOWN_ERROR")};function y(s,e){let t=s.status,r=s.statusText||"Request failed";if(typeof e=="object"&&e!==null){let a=e;r=a.error||a.message||r}else typeof e=="string"&&(r=e);let n;switch(t){case 400:n="INVALID_TOKEN";break;case 401:n="UNAUTHORIZED";break;case 403:n="UNAUTHORIZED";break;case 404:n="SERVER_ERROR";break;default:n=t>=500?"SERVER_ERROR":"UNKNOWN_ERROR"}return new o(r,n,t)}var u={ACCESS_TOKEN:"cohost_auth_access_token",REFRESH_TOKEN:"cohost_auth_refresh_token",TOKEN_EXPIRY:"cohost_auth_token_expiry",USER:"cohost_auth_user"};function O(){return typeof window<"u"&&typeof window.localStorage<"u"}var k=class{constructor(e){i(this,"storage");if(!O())throw new o("Web storage is not available in this environment","STORAGE_ERROR");this.storage=e==="localStorage"?window.localStorage:window.sessionStorage}getAccessToken(){try{return this.storage.getItem(u.ACCESS_TOKEN)}catch{return null}}setAccessToken(e){try{this.storage.setItem(u.ACCESS_TOKEN,e)}catch{throw new o("Failed to save access token","STORAGE_ERROR")}}getRefreshToken(){try{return this.storage.getItem(u.REFRESH_TOKEN)}catch{return null}}setRefreshToken(e){try{this.storage.setItem(u.REFRESH_TOKEN,e)}catch{throw new o("Failed to save refresh token","STORAGE_ERROR")}}getTokenExpiry(){try{let e=this.storage.getItem(u.TOKEN_EXPIRY);return e?parseInt(e,10):null}catch{return null}}setTokenExpiry(e){try{this.storage.setItem(u.TOKEN_EXPIRY,e.toString())}catch{throw new o("Failed to save token expiry","STORAGE_ERROR")}}getUser(){try{let e=this.storage.getItem(u.USER);return e?JSON.parse(e):null}catch{return null}}setUser(e){try{this.storage.setItem(u.USER,JSON.stringify(e))}catch{throw new o("Failed to save user","STORAGE_ERROR")}}clear(){try{this.storage.removeItem(u.ACCESS_TOKEN),this.storage.removeItem(u.REFRESH_TOKEN),this.storage.removeItem(u.TOKEN_EXPIRY),this.storage.removeItem(u.USER)}catch{}}},R=class{constructor(){i(this,"accessToken",null);i(this,"refreshToken",null);i(this,"tokenExpiry",null);i(this,"user",null)}getAccessToken(){return this.accessToken}setAccessToken(e){this.accessToken=e}getRefreshToken(){return this.refreshToken}setRefreshToken(e){this.refreshToken=e}getTokenExpiry(){return this.tokenExpiry}setTokenExpiry(e){this.tokenExpiry=e}getUser(){return this.user}setUser(e){this.user=e}clear(){this.accessToken=null,this.refreshToken=null,this.tokenExpiry=null,this.user=null}};function p(s){return s==="memory"||!O()?new R:new k(s)}var g=class{constructor(e,t=!1){i(this,"baseUrl");i(this,"debug");this.baseUrl=e.replace(/\/$/,""),this.debug=t}async request(e,t={}){let{method:r="GET",body:n,headers:a={},token:d}=t,E=`${this.baseUrl}${e}`,m={"Content-Type":"application/json",...a};d&&(m.Authorization=`Bearer ${d}`),this.debug&&(console.log(`[AuthClient] ${r} ${E}`),n&&console.log("[AuthClient] Body:",JSON.stringify(n)));let c;try{c=await fetch(E,{method:r,headers:m,body:n?JSON.stringify(n):void 0})}catch(A){throw l.networkError(A instanceof Error?A.message:"Network request failed")}let h=c.headers.get("content-type")?.includes("application/json")?await c.json():await c.text();if(this.debug&&console.log(`[AuthClient] Response (${c.status}):`,h),!c.ok)throw y(c,h);return typeof h=="object"&&h!==null&&h.status==="ok"&&"data"in h?h.data:h}async requestOTP(e){return this.request("/otp/request",{method:"POST",body:e})}async verifyOTP(e){return this.request("/otp/verify",{method:"POST",body:e})}async refreshToken(e){return this.request("/token/refresh",{method:"POST",body:e})}async validateToken(e){return this.request("/token/validate",{method:"POST",body:e})}async revokeToken(e){return this.request("/token/revoke",{method:"POST",token:e})}async getCurrentUser(e){return this.request("/me",{method:"GET",token:e})}};var N=300,T=class{constructor(e){i(this,"config");i(this,"storage");i(this,"api");i(this,"state");i(this,"listeners",new Set);i(this,"refreshTimer",null);i(this,"initialized",!1);this.config={apiUrl:e.apiUrl,channelId:e.channelId,tokenParam:e.tokenParam,storage:e.storage??"localStorage",debug:e.debug??!1,autoRefresh:e.autoRefresh??!0,refreshThreshold:e.refreshThreshold??N},this.storage=p(this.config.storage),this.api=new g(this.config.apiUrl,this.config.debug),this.state={isAuthenticated:!1,isLoading:!0,user:null,accessToken:null,error:null}}async initialize(){if(!this.initialized){this.debug("Initializing auth client");try{let e=this.storage.getAccessToken(),t=this.storage.getUser(),r=this.storage.getTokenExpiry();if(e&&t&&r){let n=Math.floor(Date.now()/1e3);if(r>n){this.updateState({isAuthenticated:!0,isLoading:!1,user:t,accessToken:e,error:null}),this.config.autoRefresh&&this.scheduleRefresh(r-n),this.initialized=!0;return}let a=this.storage.getRefreshToken();if(a){await this.performRefresh(a),this.initialized=!0;return}}this.storage.clear(),this.updateState({isAuthenticated:!1,isLoading:!1,user:null,accessToken:null,error:null})}catch(e){this.debug("Initialization error:",e),this.storage.clear(),this.updateState({isAuthenticated:!1,isLoading:!1,user:null,accessToken:null,error:o.fromError(e)})}this.initialized=!0}}getState(){return{...this.state}}onAuthStateChanged(e){return this.listeners.add(e),e(this.getState()),()=>{this.listeners.delete(e)}}get isAuthenticated(){return this.state.isAuthenticated}get currentUser(){return this.state.user}get accessToken(){return this.state.accessToken}async requestOTP(e,t="email"){this.debug("Requesting OTP for:",e,t);let r={contact:e,type:t,channelId:this.config.channelId};return(await this.api.requestOTP(r)).sent}async verifyOTP(e,t){this.debug("Verifying OTP for:",e);let r={contact:e,code:t,channelId:this.config.channelId},n=await this.api.verifyOTP(r);this.storage.setAccessToken(n.customToken),this.storage.setUser(n.user);let a=Math.floor(Date.now()/1e3)+10080*60;return this.storage.setTokenExpiry(a),this.updateState({isAuthenticated:!0,isLoading:!1,user:n.user,accessToken:n.customToken,error:null}),this.config.autoRefresh&&this.scheduleRefresh(10080*60),n.user}setAuthenticated(e){this.debug("Setting authenticated state for:",e.user.uid);let{accessToken:t,user:r,refreshToken:n,expiresIn:a=10080*60}=e;this.storage.setAccessToken(t),this.storage.setUser(r),n&&this.storage.setRefreshToken(n);let d=Math.floor(Date.now()/1e3)+a;this.storage.setTokenExpiry(d),this.updateState({isAuthenticated:!0,isLoading:!1,user:r,accessToken:t,error:null}),this.config.autoRefresh&&n&&this.scheduleRefresh(a)}get tokenParamName(){return this.config.tokenParam}async authenticateWithToken(e){this.debug("Authenticating with token"),this.updateState({...this.state,isLoading:!0,error:null});try{let t=await this.api.validateToken({accessToken:e});if(!t.valid||!t.uid)return this.debug("Token validation failed: invalid token"),this.updateState({...this.state,isLoading:!1}),{success:!1,error:"Invalid token"};let r=await this.api.getCurrentUser(e),n=Math.floor(Date.now()/1e3),a=t.exp?t.exp-n:10080*60;return this.setAuthenticated({accessToken:e,user:r.user,expiresIn:a}),this.debug("Token authentication successful for:",r.user.uid),{success:!0,user:r.user}}catch(t){return this.debug("Token authentication failed:",t),this.updateState({...this.state,isLoading:!1,error:o.fromError(t,"INVALID_TOKEN")}),{success:!1,error:t instanceof Error?t.message:"Token authentication failed"}}}async getToken(){if(!this.state.accessToken)return null;let e=this.storage.getTokenExpiry(),t=Math.floor(Date.now()/1e3);if(e&&e-t<this.config.refreshThreshold){let r=this.storage.getRefreshToken();r&&await this.performRefresh(r)}return this.state.accessToken}async refreshToken(){let e=this.storage.getRefreshToken();if(!e)throw l.notAuthenticated();await this.performRefresh(e)}async signOut(){if(this.debug("Signing out"),this.refreshTimer&&(clearTimeout(this.refreshTimer),this.refreshTimer=null),this.state.accessToken)try{await this.api.revokeToken(this.state.accessToken)}catch(e){this.debug("Revoke token error (ignored):",e)}this.storage.clear(),this.updateState({isAuthenticated:!1,isLoading:!1,user:null,accessToken:null,error:null})}async getCurrentUser(){if(!this.state.accessToken)return null;let e=await this.api.getCurrentUser(this.state.accessToken);return this.storage.setUser(e.user),this.updateState({...this.state,user:e.user}),e.user}updateState(e){this.state=e;for(let t of this.listeners)try{t(this.getState())}catch(r){this.debug("Listener error:",r)}}async performRefresh(e){this.debug("Refreshing token");try{let t=await this.api.refreshToken({refreshToken:e,channelId:this.config.channelId});this.storage.setAccessToken(t.accessToken),this.storage.setRefreshToken(t.refreshToken);let r=Math.floor(Date.now()/1e3)+t.expiresIn;this.storage.setTokenExpiry(r),this.updateState({...this.state,accessToken:t.accessToken,error:null}),this.config.autoRefresh&&this.scheduleRefresh(t.expiresIn)}catch(t){this.debug("Refresh failed:",t),this.storage.clear(),this.updateState({isAuthenticated:!1,isLoading:!1,user:null,accessToken:null,error:o.fromError(t,"TOKEN_EXPIRED")})}}scheduleRefresh(e){this.refreshTimer&&clearTimeout(this.refreshTimer);let t=Math.max(0,e-this.config.refreshThreshold)*1e3;this.debug(`Scheduling refresh in ${t/1e3}s`),this.refreshTimer=setTimeout(()=>{let r=this.storage.getRefreshToken();r&&this.performRefresh(r)},t)}debug(...e){this.config.debug&&console.log("[AuthClient]",...e)}};function U(s){return new T(s)}0&&(module.exports={AuthApi,AuthClient,AuthError,authErrors,createAuthClient,createStorage});
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/types.ts","../src/errors.ts","../src/storage.ts","../src/api.ts","../src/client.ts"],"sourcesContent":["// Main exports\nexport { AuthClient } from './client';\nexport { AuthApi } from './api';\n\n// Storage\nexport { createStorage, type TokenStorage } from './storage';\n\n// Types\nexport {\n type AuthConfig,\n type AuthState,\n type AuthUser,\n type AuthResult,\n type TokenPair,\n type AuthStateListener,\n type Unsubscribe,\n type OTPType,\n type OTPRequestInput,\n type OTPVerifyInput,\n type SetAuthenticatedInput,\n type TokenRefreshInput,\n type TokenValidateInput,\n type TokenValidateResult,\n type AuthErrorCode,\n AuthError,\n} from './types';\n\n// Errors\nexport { authErrors } from './errors';\n\nimport { AuthClient } from './client';\nimport { AuthConfig } from './types';\n\n/**\n * Factory function for creating an AuthClient instance\n *\n * @example\n * ```ts\n * import { createAuthClient } from '@cohostvip/cohost-auth';\n *\n * // apiUrl should include the auth path prefix\n * const auth = createAuthClient({\n * apiUrl: 'https://api.cohost.vip/v1/auth', // or '/auth' for relative paths\n * channelId: 'my-channel',\n * });\n *\n * await auth.initialize();\n *\n * // Request OTP (email or phone)\n * await auth.requestOTP('user@example.com', 'email');\n * await auth.requestOTP('+1234567890', 'phone');\n *\n * // Verify OTP\n * const user = await auth.verifyOTP('user@example.com', '123456');\n *\n * // For custom auth flows (e.g., passkey), use setAuthenticated\n * auth.setAuthenticated({\n * accessToken: 'token-from-custom-flow',\n * user: { uid: '123', email: 'user@example.com', ... },\n * });\n *\n * // Check auth state\n * if (auth.isAuthenticated) {\n * console.log('Logged in as:', auth.currentUser?.email);\n * }\n *\n * // Listen for auth changes\n * auth.onAuthStateChanged((state) => {\n * console.log('Auth state changed:', state);\n * });\n *\n * // Sign out\n * await auth.signOut();\n * ```\n */\nexport function createAuthClient(config: AuthConfig): AuthClient {\n return new AuthClient(config);\n}\n","/**\n * Configuration options for initializing AuthClient\n */\nexport interface AuthConfig {\n /** Base URL for the auth API (e.g., 'https://api.cohost.vip' or '/api') */\n apiUrl: string;\n /** Optional channel ID for multi-tenant scenarios */\n channelId?: string;\n /** Storage type for tokens (default: 'localStorage') */\n storage?: 'localStorage' | 'sessionStorage' | 'memory';\n /** Enable debug logging */\n debug?: boolean;\n /** Auto-refresh tokens before expiry (default: true) */\n autoRefresh?: boolean;\n /** Refresh tokens this many seconds before expiry (default: 300 = 5 minutes) */\n refreshThreshold?: number;\n}\n\n/**\n * User object returned from auth endpoints\n */\nexport interface AuthUser {\n uid: string;\n email: string;\n emailVerified: boolean;\n displayName?: string;\n photoURL?: string;\n phoneNumber?: string;\n provider: string;\n providerId: string;\n}\n\n/**\n * Token pair returned from authentication\n */\nexport interface TokenPair {\n accessToken: string;\n refreshToken: string;\n expiresIn: number;\n}\n\n/**\n * Result from authentication operations (sign-in, verify OTP, etc.)\n */\nexport interface AuthResult {\n user: AuthUser;\n customToken: string;\n isNewUser: boolean;\n}\n\n/**\n * Current authentication state\n */\nexport interface AuthState {\n /** Whether the user is authenticated */\n isAuthenticated: boolean;\n /** Whether auth state is being loaded/verified */\n isLoading: boolean;\n /** Current user if authenticated */\n user: AuthUser | null;\n /** Access token if authenticated */\n accessToken: string | null;\n /** Error if last operation failed */\n error: AuthError | null;\n}\n\n/**\n * Callback type for auth state changes\n */\nexport type AuthStateListener = (state: AuthState) => void;\n\n/**\n * Unsubscribe function returned from onAuthStateChanged\n */\nexport type Unsubscribe = () => void;\n\n/**\n * OTP contact type\n */\nexport type OTPType = 'email' | 'phone';\n\n/**\n * OTP request input\n */\nexport interface OTPRequestInput {\n /** Contact (email or phone) to send OTP to */\n contact: string;\n /** Type of contact */\n type: OTPType;\n /** Optional channel ID */\n channelId?: string;\n}\n\n/**\n * OTP verify input\n */\nexport interface OTPVerifyInput {\n /** Contact (email or phone) that received the OTP */\n contact: string;\n /** OTP code to verify */\n code: string;\n /** Optional channel ID */\n channelId?: string;\n}\n\n/**\n * Input for manually setting authenticated state (for custom auth flows)\n */\nexport interface SetAuthenticatedInput {\n /** Access token */\n accessToken: string;\n /** User object */\n user: AuthUser;\n /** Refresh token (optional) */\n refreshToken?: string;\n /** Token expiry in seconds (default: 7 days) */\n expiresIn?: number;\n}\n\n/**\n * Token refresh input\n */\nexport interface TokenRefreshInput {\n /** Refresh token to exchange for new tokens */\n refreshToken: string;\n /** Optional channel ID */\n channelId?: string;\n}\n\n/**\n * Token validate input\n */\nexport interface TokenValidateInput {\n /** Access token to validate */\n accessToken: string;\n}\n\n/**\n * Token validate response\n */\nexport interface TokenValidateResult {\n valid: boolean;\n uid?: string;\n channelId?: string;\n exp?: number;\n iat?: number;\n}\n\n/**\n * Error codes for auth operations\n */\nexport type AuthErrorCode =\n | 'INVALID_EMAIL'\n | 'INVALID_PHONE'\n | 'INVALID_CONTACT'\n | 'INVALID_OTP'\n | 'OTP_EXPIRED'\n | 'INVALID_TOKEN'\n | 'TOKEN_EXPIRED'\n | 'NETWORK_ERROR'\n | 'SERVER_ERROR'\n | 'UNAUTHORIZED'\n | 'NOT_AUTHENTICATED'\n | 'STORAGE_ERROR'\n | 'UNKNOWN_ERROR';\n\n/**\n * Auth error with typed error codes\n */\nexport class AuthError extends Error {\n code: AuthErrorCode;\n statusCode?: number;\n originalError?: Error;\n\n constructor(message: string, code: AuthErrorCode, statusCode?: number, originalError?: Error) {\n super(message);\n this.name = 'AuthError';\n this.code = code;\n this.statusCode = statusCode;\n this.originalError = originalError;\n }\n\n static fromError(error: Error, code: AuthErrorCode = 'UNKNOWN_ERROR'): AuthError {\n if (error instanceof AuthError) {\n return error;\n }\n return new AuthError(error.message, code, undefined, error);\n }\n}\n","import { AuthError, AuthErrorCode } from './types';\n\n/**\n * Factory functions for creating typed auth errors\n */\nexport const authErrors = {\n invalidEmail: () => new AuthError('Invalid email address', 'INVALID_EMAIL', 400),\n\n invalidOTP: () => new AuthError('Invalid or incorrect OTP code', 'INVALID_OTP', 400),\n\n otpExpired: () => new AuthError('OTP code has expired', 'OTP_EXPIRED', 400),\n\n invalidToken: () => new AuthError('Invalid token', 'INVALID_TOKEN', 401),\n\n tokenExpired: () => new AuthError('Token has expired', 'TOKEN_EXPIRED', 401),\n\n networkError: (message = 'Network request failed') =>\n new AuthError(message, 'NETWORK_ERROR'),\n\n serverError: (message = 'Server error', statusCode = 500) =>\n new AuthError(message, 'SERVER_ERROR', statusCode),\n\n unauthorized: () => new AuthError('Unauthorized', 'UNAUTHORIZED', 401),\n\n notAuthenticated: () => new AuthError('User is not authenticated', 'NOT_AUTHENTICATED'),\n\n storageError: (message = 'Storage operation failed') =>\n new AuthError(message, 'STORAGE_ERROR'),\n\n unknown: (message = 'An unknown error occurred') =>\n new AuthError(message, 'UNKNOWN_ERROR'),\n};\n\n/**\n * Parse error response from API\n */\nexport function parseApiError(response: Response, body: unknown): AuthError {\n const statusCode = response.status;\n\n // Try to extract error message from response body\n let message = response.statusText || 'Request failed';\n if (typeof body === 'object' && body !== null) {\n const errorBody = body as { error?: string; message?: string };\n message = errorBody.error || errorBody.message || message;\n } else if (typeof body === 'string') {\n message = body;\n }\n\n // Map status codes to error codes\n let code: AuthErrorCode;\n switch (statusCode) {\n case 400:\n // Could be invalid email, invalid OTP, etc. - use generic for now\n code = 'INVALID_TOKEN';\n break;\n case 401:\n code = 'UNAUTHORIZED';\n break;\n case 403:\n code = 'UNAUTHORIZED';\n break;\n case 404:\n code = 'SERVER_ERROR';\n break;\n default:\n code = statusCode >= 500 ? 'SERVER_ERROR' : 'UNKNOWN_ERROR';\n }\n\n return new AuthError(message, code, statusCode);\n}\n","import { AuthError } from './types';\n\nconst TOKEN_KEYS = {\n ACCESS_TOKEN: 'cohost_auth_access_token',\n REFRESH_TOKEN: 'cohost_auth_refresh_token',\n TOKEN_EXPIRY: 'cohost_auth_token_expiry',\n USER: 'cohost_auth_user',\n} as const;\n\n/**\n * Storage abstraction interface for token persistence\n */\nexport interface TokenStorage {\n getAccessToken(): string | null;\n setAccessToken(token: string): void;\n getRefreshToken(): string | null;\n setRefreshToken(token: string): void;\n getTokenExpiry(): number | null;\n setTokenExpiry(expiry: number): void;\n getUser<T>(): T | null;\n setUser<T>(user: T): void;\n clear(): void;\n}\n\n/**\n * Check if we're in a browser environment\n */\nfunction isBrowser(): boolean {\n return typeof window !== 'undefined' && typeof window.localStorage !== 'undefined';\n}\n\n/**\n * Web storage implementation (localStorage/sessionStorage)\n */\nclass WebStorage implements TokenStorage {\n private storage: Storage;\n\n constructor(type: 'localStorage' | 'sessionStorage') {\n if (!isBrowser()) {\n throw new AuthError(\n 'Web storage is not available in this environment',\n 'STORAGE_ERROR'\n );\n }\n this.storage = type === 'localStorage' ? window.localStorage : window.sessionStorage;\n }\n\n getAccessToken(): string | null {\n try {\n return this.storage.getItem(TOKEN_KEYS.ACCESS_TOKEN);\n } catch {\n return null;\n }\n }\n\n setAccessToken(token: string): void {\n try {\n this.storage.setItem(TOKEN_KEYS.ACCESS_TOKEN, token);\n } catch (error) {\n throw new AuthError('Failed to save access token', 'STORAGE_ERROR');\n }\n }\n\n getRefreshToken(): string | null {\n try {\n return this.storage.getItem(TOKEN_KEYS.REFRESH_TOKEN);\n } catch {\n return null;\n }\n }\n\n setRefreshToken(token: string): void {\n try {\n this.storage.setItem(TOKEN_KEYS.REFRESH_TOKEN, token);\n } catch (error) {\n throw new AuthError('Failed to save refresh token', 'STORAGE_ERROR');\n }\n }\n\n getTokenExpiry(): number | null {\n try {\n const expiry = this.storage.getItem(TOKEN_KEYS.TOKEN_EXPIRY);\n return expiry ? parseInt(expiry, 10) : null;\n } catch {\n return null;\n }\n }\n\n setTokenExpiry(expiry: number): void {\n try {\n this.storage.setItem(TOKEN_KEYS.TOKEN_EXPIRY, expiry.toString());\n } catch (error) {\n throw new AuthError('Failed to save token expiry', 'STORAGE_ERROR');\n }\n }\n\n getUser<T>(): T | null {\n try {\n const user = this.storage.getItem(TOKEN_KEYS.USER);\n return user ? JSON.parse(user) : null;\n } catch {\n return null;\n }\n }\n\n setUser<T>(user: T): void {\n try {\n this.storage.setItem(TOKEN_KEYS.USER, JSON.stringify(user));\n } catch (error) {\n throw new AuthError('Failed to save user', 'STORAGE_ERROR');\n }\n }\n\n clear(): void {\n try {\n this.storage.removeItem(TOKEN_KEYS.ACCESS_TOKEN);\n this.storage.removeItem(TOKEN_KEYS.REFRESH_TOKEN);\n this.storage.removeItem(TOKEN_KEYS.TOKEN_EXPIRY);\n this.storage.removeItem(TOKEN_KEYS.USER);\n } catch {\n // Silently fail on clear errors\n }\n }\n}\n\n/**\n * In-memory storage implementation (for SSR or non-browser environments)\n */\nclass MemoryStorage implements TokenStorage {\n private accessToken: string | null = null;\n private refreshToken: string | null = null;\n private tokenExpiry: number | null = null;\n private user: unknown = null;\n\n getAccessToken(): string | null {\n return this.accessToken;\n }\n\n setAccessToken(token: string): void {\n this.accessToken = token;\n }\n\n getRefreshToken(): string | null {\n return this.refreshToken;\n }\n\n setRefreshToken(token: string): void {\n this.refreshToken = token;\n }\n\n getTokenExpiry(): number | null {\n return this.tokenExpiry;\n }\n\n setTokenExpiry(expiry: number): void {\n this.tokenExpiry = expiry;\n }\n\n getUser<T>(): T | null {\n return this.user as T | null;\n }\n\n setUser<T>(user: T): void {\n this.user = user;\n }\n\n clear(): void {\n this.accessToken = null;\n this.refreshToken = null;\n this.tokenExpiry = null;\n this.user = null;\n }\n}\n\n/**\n * Create a storage instance based on type\n */\nexport function createStorage(type: 'localStorage' | 'sessionStorage' | 'memory'): TokenStorage {\n if (type === 'memory' || !isBrowser()) {\n return new MemoryStorage();\n }\n return new WebStorage(type);\n}\n\nexport { MemoryStorage, WebStorage };\n","import {\n AuthResult,\n AuthUser,\n TokenPair,\n TokenValidateResult,\n OTPRequestInput,\n OTPVerifyInput,\n TokenRefreshInput,\n TokenValidateInput,\n} from './types';\nimport { parseApiError, authErrors } from './errors';\n\n/**\n * API response wrapper\n */\ninterface ApiResponse<T> {\n status: 'ok' | 'error';\n data: T;\n}\n\n/**\n * Options for API requests\n */\ninterface RequestOptions {\n method?: 'GET' | 'POST' | 'PUT' | 'DELETE';\n body?: unknown;\n headers?: Record<string, string>;\n token?: string;\n}\n\n/**\n * Auth API client for making requests to auth endpoints\n */\nexport class AuthApi {\n private baseUrl: string;\n private debug: boolean;\n\n constructor(baseUrl: string, debug = false) {\n // Remove trailing slash if present\n this.baseUrl = baseUrl.replace(/\\/$/, '');\n this.debug = debug;\n }\n\n /**\n * Make an authenticated or unauthenticated request\n */\n private async request<T>(path: string, options: RequestOptions = {}): Promise<T> {\n const { method = 'GET', body, headers = {}, token } = options;\n\n const url = `${this.baseUrl}${path}`;\n\n const reqHeaders: Record<string, string> = {\n 'Content-Type': 'application/json',\n ...headers,\n };\n\n if (token) {\n reqHeaders['Authorization'] = `Bearer ${token}`;\n }\n\n if (this.debug) {\n console.log(`[AuthClient] ${method} ${url}`);\n if (body) {\n console.log('[AuthClient] Body:', JSON.stringify(body));\n }\n }\n\n let response: Response;\n try {\n response = await fetch(url, {\n method,\n headers: reqHeaders,\n body: body ? JSON.stringify(body) : undefined,\n });\n } catch (error) {\n throw authErrors.networkError(\n error instanceof Error ? error.message : 'Network request failed'\n );\n }\n\n const isJson = response.headers.get('content-type')?.includes('application/json');\n const responseBody = isJson ? await response.json() : await response.text();\n\n if (this.debug) {\n console.log(`[AuthClient] Response (${response.status}):`, responseBody);\n }\n\n if (!response.ok) {\n throw parseApiError(response, responseBody);\n }\n\n // Unwrap API response format { status: 'ok', data: ... }\n if (\n typeof responseBody === 'object' &&\n responseBody !== null &&\n (responseBody as ApiResponse<T>).status === 'ok' &&\n 'data' in responseBody\n ) {\n return (responseBody as ApiResponse<T>).data;\n }\n\n return responseBody as T;\n }\n\n // === OTP Methods ===\n\n /**\n * Request OTP code to be sent to contact (email or phone)\n */\n async requestOTP(input: OTPRequestInput): Promise<{ sent: boolean }> {\n return this.request('/otp/request', {\n method: 'POST',\n body: input,\n });\n }\n\n /**\n * Verify OTP code and get auth result\n */\n async verifyOTP(input: OTPVerifyInput): Promise<AuthResult> {\n return this.request('/otp/verify', {\n method: 'POST',\n body: input,\n });\n }\n\n // === Token Methods ===\n\n /**\n * Refresh token pair using refresh token\n */\n async refreshToken(input: TokenRefreshInput): Promise<TokenPair> {\n return this.request('/token/refresh', {\n method: 'POST',\n body: input,\n });\n }\n\n /**\n * Validate access token\n */\n async validateToken(input: TokenValidateInput): Promise<TokenValidateResult> {\n return this.request('/token/validate', {\n method: 'POST',\n body: input,\n });\n }\n\n /**\n * Revoke token (sign out)\n */\n async revokeToken(token: string): Promise<{ revoked: boolean }> {\n return this.request('/token/revoke', {\n method: 'POST',\n token,\n });\n }\n\n // === User Methods ===\n\n /**\n * Get current authenticated user\n */\n async getCurrentUser(token: string): Promise<{ user: AuthUser; channelId?: string }> {\n return this.request('/me', {\n method: 'GET',\n token,\n });\n }\n}\n","import {\n AuthConfig,\n AuthState,\n AuthUser,\n AuthStateListener,\n Unsubscribe,\n AuthError,\n OTPRequestInput,\n OTPVerifyInput,\n OTPType,\n SetAuthenticatedInput,\n} from './types';\nimport { authErrors } from './errors';\nimport { createStorage, TokenStorage } from './storage';\nimport { AuthApi } from './api';\n\nconst DEFAULT_REFRESH_THRESHOLD = 300; // 5 minutes in seconds\n\n/**\n * Main auth client class for managing authentication state\n */\nexport class AuthClient {\n private config: Required<Omit<AuthConfig, 'channelId'>> & { channelId?: string };\n private storage: TokenStorage;\n private api: AuthApi;\n private state: AuthState;\n private listeners: Set<AuthStateListener> = new Set();\n private refreshTimer: ReturnType<typeof setTimeout> | null = null;\n private initialized = false;\n\n constructor(config: AuthConfig) {\n this.config = {\n apiUrl: config.apiUrl,\n channelId: config.channelId,\n storage: config.storage ?? 'localStorage',\n debug: config.debug ?? false,\n autoRefresh: config.autoRefresh ?? true,\n refreshThreshold: config.refreshThreshold ?? DEFAULT_REFRESH_THRESHOLD,\n };\n\n this.storage = createStorage(this.config.storage);\n this.api = new AuthApi(this.config.apiUrl, this.config.debug);\n\n // Initialize state\n this.state = {\n isAuthenticated: false,\n isLoading: true,\n user: null,\n accessToken: null,\n error: null,\n };\n }\n\n /**\n * Initialize the auth client by loading saved state\n */\n async initialize(): Promise<void> {\n if (this.initialized) {\n return;\n }\n\n this.debug('Initializing auth client');\n\n try {\n const accessToken = this.storage.getAccessToken();\n const user = this.storage.getUser<AuthUser>();\n const expiry = this.storage.getTokenExpiry();\n\n if (accessToken && user && expiry) {\n // Check if token is expired\n const now = Math.floor(Date.now() / 1000);\n if (expiry > now) {\n // Token is valid, restore state\n this.updateState({\n isAuthenticated: true,\n isLoading: false,\n user,\n accessToken,\n error: null,\n });\n\n // Set up auto-refresh if enabled\n if (this.config.autoRefresh) {\n this.scheduleRefresh(expiry - now);\n }\n\n this.initialized = true;\n return;\n }\n\n // Token expired, try to refresh\n const refreshToken = this.storage.getRefreshToken();\n if (refreshToken) {\n await this.performRefresh(refreshToken);\n this.initialized = true;\n return;\n }\n }\n\n // No valid session, clear and set as not authenticated\n this.storage.clear();\n this.updateState({\n isAuthenticated: false,\n isLoading: false,\n user: null,\n accessToken: null,\n error: null,\n });\n } catch (error) {\n this.debug('Initialization error:', error);\n this.storage.clear();\n this.updateState({\n isAuthenticated: false,\n isLoading: false,\n user: null,\n accessToken: null,\n error: AuthError.fromError(error as Error),\n });\n }\n\n this.initialized = true;\n }\n\n // === Public API ===\n\n /**\n * Get current auth state\n */\n getState(): AuthState {\n return { ...this.state };\n }\n\n /**\n * Subscribe to auth state changes\n */\n onAuthStateChanged(listener: AuthStateListener): Unsubscribe {\n this.listeners.add(listener);\n // Immediately call with current state\n listener(this.getState());\n return () => {\n this.listeners.delete(listener);\n };\n }\n\n /**\n * Check if user is authenticated\n */\n get isAuthenticated(): boolean {\n return this.state.isAuthenticated;\n }\n\n /**\n * Get current user\n */\n get currentUser(): AuthUser | null {\n return this.state.user;\n }\n\n /**\n * Get current access token\n */\n get accessToken(): string | null {\n return this.state.accessToken;\n }\n\n // === OTP Authentication ===\n\n /**\n * Request OTP code to be sent to contact (email or phone)\n * @param contact - Email address or phone number\n * @param type - Type of contact ('email' or 'phone')\n */\n async requestOTP(contact: string, type: OTPType = 'email'): Promise<boolean> {\n this.debug('Requesting OTP for:', contact, type);\n\n const input: OTPRequestInput = {\n contact,\n type,\n channelId: this.config.channelId,\n };\n\n const result = await this.api.requestOTP(input);\n return result.sent;\n }\n\n /**\n * Verify OTP code and sign in\n * @param contact - Email address or phone number that received the OTP\n * @param code - OTP code to verify\n */\n async verifyOTP(contact: string, code: string): Promise<AuthUser> {\n this.debug('Verifying OTP for:', contact);\n\n const input: OTPVerifyInput = {\n contact,\n code,\n channelId: this.config.channelId,\n };\n\n const result = await this.api.verifyOTP(input);\n\n // The customToken from verifyOTP is a JWT that we use as our access token\n // We need to also get a refresh token by calling refresh endpoint\n // For now, we'll store the customToken as access token\n // TODO: Backend should return both access and refresh tokens\n\n // Store tokens and user\n this.storage.setAccessToken(result.customToken);\n this.storage.setUser(result.user);\n\n // Set expiry (assume 7 days if not provided)\n const expiry = Math.floor(Date.now() / 1000) + 7 * 24 * 60 * 60;\n this.storage.setTokenExpiry(expiry);\n\n this.updateState({\n isAuthenticated: true,\n isLoading: false,\n user: result.user,\n accessToken: result.customToken,\n error: null,\n });\n\n if (this.config.autoRefresh) {\n this.scheduleRefresh(7 * 24 * 60 * 60);\n }\n\n return result.user;\n }\n\n // === Custom Auth Flow ===\n\n /**\n * Manually set authenticated state after a custom auth flow (e.g., passkey)\n * Use this when you handle authentication outside the standard OTP flow\n */\n setAuthenticated(input: SetAuthenticatedInput): void {\n this.debug('Setting authenticated state for:', input.user.uid);\n\n const { accessToken, user, refreshToken, expiresIn = 7 * 24 * 60 * 60 } = input;\n\n // Store tokens and user\n this.storage.setAccessToken(accessToken);\n this.storage.setUser(user);\n\n if (refreshToken) {\n this.storage.setRefreshToken(refreshToken);\n }\n\n const expiry = Math.floor(Date.now() / 1000) + expiresIn;\n this.storage.setTokenExpiry(expiry);\n\n this.updateState({\n isAuthenticated: true,\n isLoading: false,\n user,\n accessToken,\n error: null,\n });\n\n if (this.config.autoRefresh && refreshToken) {\n this.scheduleRefresh(expiresIn);\n }\n }\n\n // === Token Management ===\n\n /**\n * Get current access token, refreshing if needed\n */\n async getToken(): Promise<string | null> {\n if (!this.state.accessToken) {\n return null;\n }\n\n // Check if token needs refresh\n const expiry = this.storage.getTokenExpiry();\n const now = Math.floor(Date.now() / 1000);\n\n if (expiry && expiry - now < this.config.refreshThreshold) {\n const refreshToken = this.storage.getRefreshToken();\n if (refreshToken) {\n await this.performRefresh(refreshToken);\n }\n }\n\n return this.state.accessToken;\n }\n\n /**\n * Manually refresh the token\n */\n async refreshToken(): Promise<void> {\n const refreshToken = this.storage.getRefreshToken();\n if (!refreshToken) {\n throw authErrors.notAuthenticated();\n }\n await this.performRefresh(refreshToken);\n }\n\n /**\n * Sign out and clear all tokens\n */\n async signOut(): Promise<void> {\n this.debug('Signing out');\n\n // Cancel any pending refresh\n if (this.refreshTimer) {\n clearTimeout(this.refreshTimer);\n this.refreshTimer = null;\n }\n\n // Try to revoke token on server (best effort)\n if (this.state.accessToken) {\n try {\n await this.api.revokeToken(this.state.accessToken);\n } catch (error) {\n this.debug('Revoke token error (ignored):', error);\n }\n }\n\n // Clear storage\n this.storage.clear();\n\n // Update state\n this.updateState({\n isAuthenticated: false,\n isLoading: false,\n user: null,\n accessToken: null,\n error: null,\n });\n }\n\n // === User ===\n\n /**\n * Get current user from server\n */\n async getCurrentUser(): Promise<AuthUser | null> {\n if (!this.state.accessToken) {\n return null;\n }\n\n const result = await this.api.getCurrentUser(this.state.accessToken);\n\n // Update stored user\n this.storage.setUser(result.user);\n this.updateState({\n ...this.state,\n user: result.user,\n });\n\n return result.user;\n }\n\n // === Private Methods ===\n\n private updateState(newState: AuthState): void {\n this.state = newState;\n // Notify all listeners\n for (const listener of this.listeners) {\n try {\n listener(this.getState());\n } catch (error) {\n this.debug('Listener error:', error);\n }\n }\n }\n\n private async performRefresh(refreshToken: string): Promise<void> {\n this.debug('Refreshing token');\n\n try {\n const result = await this.api.refreshToken({\n refreshToken,\n channelId: this.config.channelId,\n });\n\n // Store new tokens\n this.storage.setAccessToken(result.accessToken);\n this.storage.setRefreshToken(result.refreshToken);\n\n const expiry = Math.floor(Date.now() / 1000) + result.expiresIn;\n this.storage.setTokenExpiry(expiry);\n\n // Update state with new token\n this.updateState({\n ...this.state,\n accessToken: result.accessToken,\n error: null,\n });\n\n // Schedule next refresh\n if (this.config.autoRefresh) {\n this.scheduleRefresh(result.expiresIn);\n }\n } catch (error) {\n this.debug('Refresh failed:', error);\n // On refresh failure, sign out\n this.storage.clear();\n this.updateState({\n isAuthenticated: false,\n isLoading: false,\n user: null,\n accessToken: null,\n error: AuthError.fromError(error as Error, 'TOKEN_EXPIRED'),\n });\n }\n }\n\n private scheduleRefresh(expiresIn: number): void {\n if (this.refreshTimer) {\n clearTimeout(this.refreshTimer);\n }\n\n // Refresh when threshold is reached\n const refreshIn = Math.max(0, expiresIn - this.config.refreshThreshold) * 1000;\n\n this.debug(`Scheduling refresh in ${refreshIn / 1000}s`);\n\n this.refreshTimer = setTimeout(() => {\n const refreshToken = this.storage.getRefreshToken();\n if (refreshToken) {\n this.performRefresh(refreshToken);\n }\n }, refreshIn);\n }\n\n private debug(...args: unknown[]): void {\n if (this.config.debug) {\n console.log('[AuthClient]', ...args);\n }\n }\n}\n"],"mappings":"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","names":["index_exports","__export","AuthApi","AuthClient","AuthError","authErrors","createAuthClient","createStorage","__toCommonJS","AuthError","_AuthError","message","code","statusCode","originalError","__publicField","error","authErrors","AuthError","message","statusCode","parseApiError","response","body","errorBody","code","TOKEN_KEYS","isBrowser","WebStorage","type","__publicField","AuthError","token","expiry","user","MemoryStorage","createStorage","AuthApi","baseUrl","debug","__publicField","path","options","method","body","headers","token","url","reqHeaders","response","error","authErrors","responseBody","parseApiError","input","DEFAULT_REFRESH_THRESHOLD","AuthClient","config","__publicField","createStorage","AuthApi","accessToken","user","expiry","now","refreshToken","error","AuthError","listener","contact","type","input","code","result","expiresIn","authErrors","newState","refreshIn","args","createAuthClient","config","AuthClient"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/types.ts","../src/errors.ts","../src/storage.ts","../src/api.ts","../src/client.ts"],"sourcesContent":["// Main exports\nexport { AuthClient } from './client';\nexport { AuthApi } from './api';\n\n// Storage\nexport { createStorage, type TokenStorage } from './storage';\n\n// Types\nexport {\n type AuthConfig,\n type AuthState,\n type AuthUser,\n type AuthResult,\n type TokenPair,\n type AuthStateListener,\n type Unsubscribe,\n type OTPType,\n type OTPRequestInput,\n type OTPVerifyInput,\n type SetAuthenticatedInput,\n type TokenRefreshInput,\n type TokenValidateInput,\n type TokenValidateResult,\n type TokenAuthResult,\n type AuthErrorCode,\n AuthError,\n} from './types';\n\n// Errors\nexport { authErrors } from './errors';\n\nimport { AuthClient } from './client';\nimport { AuthConfig } from './types';\n\n/**\n * Factory function for creating an AuthClient instance\n *\n * @example\n * ```ts\n * import { createAuthClient } from '@cohostvip/cohost-auth';\n *\n * // apiUrl should include the auth path prefix\n * const auth = createAuthClient({\n * apiUrl: 'https://api.cohost.vip/v1/auth', // or '/auth' for relative paths\n * channelId: 'my-channel',\n * });\n *\n * await auth.initialize();\n *\n * // Request OTP (email or phone)\n * await auth.requestOTP('user@example.com', 'email');\n * await auth.requestOTP('+1234567890', 'phone');\n *\n * // Verify OTP\n * const user = await auth.verifyOTP('user@example.com', '123456');\n *\n * // For custom auth flows (e.g., passkey), use setAuthenticated\n * auth.setAuthenticated({\n * accessToken: 'token-from-custom-flow',\n * user: { uid: '123', email: 'user@example.com', ... },\n * });\n *\n * // Check auth state\n * if (auth.isAuthenticated) {\n * console.log('Logged in as:', auth.currentUser?.email);\n * }\n *\n * // Listen for auth changes\n * auth.onAuthStateChanged((state) => {\n * console.log('Auth state changed:', state);\n * });\n *\n * // Sign out\n * await auth.signOut();\n * ```\n */\nexport function createAuthClient(config: AuthConfig): AuthClient {\n return new AuthClient(config);\n}\n","/**\n * Configuration options for initializing AuthClient\n */\nexport interface AuthConfig {\n /** Base URL for the auth API (e.g., 'https://api.cohost.vip' or '/api') */\n apiUrl: string;\n /** Optional channel ID for multi-tenant scenarios */\n channelId?: string;\n /** Storage type for tokens (default: 'localStorage') */\n storage?: 'localStorage' | 'sessionStorage' | 'memory';\n /** Enable debug logging */\n debug?: boolean;\n /** Auto-refresh tokens before expiry (default: true) */\n autoRefresh?: boolean;\n /** Refresh tokens this many seconds before expiry (default: 300 = 5 minutes) */\n refreshThreshold?: number;\n /**\n * Query string parameter name for token-based authentication (e.g., 'token' or 't').\n * If set, the client will check for this param and attempt to authenticate with it.\n * If not set, token param detection is disabled.\n */\n tokenParam?: string;\n}\n\n/**\n * User object returned from auth endpoints\n */\nexport interface AuthUser {\n uid: string;\n email: string;\n emailVerified: boolean;\n displayName?: string;\n photoURL?: string;\n phoneNumber?: string;\n provider: string;\n providerId: string;\n}\n\n/**\n * Token pair returned from authentication\n */\nexport interface TokenPair {\n accessToken: string;\n refreshToken: string;\n expiresIn: number;\n}\n\n/**\n * Result from authentication operations (sign-in, verify OTP, etc.)\n */\nexport interface AuthResult {\n user: AuthUser;\n customToken: string;\n isNewUser: boolean;\n}\n\n/**\n * Current authentication state\n */\nexport interface AuthState {\n /** Whether the user is authenticated */\n isAuthenticated: boolean;\n /** Whether auth state is being loaded/verified */\n isLoading: boolean;\n /** Current user if authenticated */\n user: AuthUser | null;\n /** Access token if authenticated */\n accessToken: string | null;\n /** Error if last operation failed */\n error: AuthError | null;\n}\n\n/**\n * Callback type for auth state changes\n */\nexport type AuthStateListener = (state: AuthState) => void;\n\n/**\n * Unsubscribe function returned from onAuthStateChanged\n */\nexport type Unsubscribe = () => void;\n\n/**\n * OTP contact type\n */\nexport type OTPType = 'email' | 'phone';\n\n/**\n * OTP request input\n */\nexport interface OTPRequestInput {\n /** Contact (email or phone) to send OTP to */\n contact: string;\n /** Type of contact */\n type: OTPType;\n /** Optional channel ID */\n channelId?: string;\n}\n\n/**\n * OTP verify input\n */\nexport interface OTPVerifyInput {\n /** Contact (email or phone) that received the OTP */\n contact: string;\n /** OTP code to verify */\n code: string;\n /** Optional channel ID */\n channelId?: string;\n}\n\n/**\n * Input for manually setting authenticated state (for custom auth flows)\n */\nexport interface SetAuthenticatedInput {\n /** Access token */\n accessToken: string;\n /** User object */\n user: AuthUser;\n /** Refresh token (optional) */\n refreshToken?: string;\n /** Token expiry in seconds (default: 7 days) */\n expiresIn?: number;\n}\n\n/**\n * Token refresh input\n */\nexport interface TokenRefreshInput {\n /** Refresh token to exchange for new tokens */\n refreshToken: string;\n /** Optional channel ID */\n channelId?: string;\n}\n\n/**\n * Token validate input\n */\nexport interface TokenValidateInput {\n /** Access token to validate */\n accessToken: string;\n}\n\n/**\n * Token validate response\n */\nexport interface TokenValidateResult {\n valid: boolean;\n uid?: string;\n channelId?: string;\n exp?: number;\n iat?: number;\n}\n\n/**\n * Result from authenticating with a token\n */\nexport interface TokenAuthResult {\n /** Whether authentication succeeded */\n success: boolean;\n /** User if authentication succeeded */\n user?: AuthUser;\n /** Error message if authentication failed */\n error?: string;\n}\n\n/**\n * Error codes for auth operations\n */\nexport type AuthErrorCode =\n | 'INVALID_EMAIL'\n | 'INVALID_PHONE'\n | 'INVALID_CONTACT'\n | 'INVALID_OTP'\n | 'OTP_EXPIRED'\n | 'INVALID_TOKEN'\n | 'TOKEN_EXPIRED'\n | 'NETWORK_ERROR'\n | 'SERVER_ERROR'\n | 'UNAUTHORIZED'\n | 'NOT_AUTHENTICATED'\n | 'STORAGE_ERROR'\n | 'UNKNOWN_ERROR';\n\n/**\n * Auth error with typed error codes\n */\nexport class AuthError extends Error {\n code: AuthErrorCode;\n statusCode?: number;\n originalError?: Error;\n\n constructor(message: string, code: AuthErrorCode, statusCode?: number, originalError?: Error) {\n super(message);\n this.name = 'AuthError';\n this.code = code;\n this.statusCode = statusCode;\n this.originalError = originalError;\n }\n\n static fromError(error: Error, code: AuthErrorCode = 'UNKNOWN_ERROR'): AuthError {\n if (error instanceof AuthError) {\n return error;\n }\n return new AuthError(error.message, code, undefined, error);\n }\n}\n","import { AuthError, AuthErrorCode } from './types';\n\n/**\n * Factory functions for creating typed auth errors\n */\nexport const authErrors = {\n invalidEmail: () => new AuthError('Invalid email address', 'INVALID_EMAIL', 400),\n\n invalidOTP: () => new AuthError('Invalid or incorrect OTP code', 'INVALID_OTP', 400),\n\n otpExpired: () => new AuthError('OTP code has expired', 'OTP_EXPIRED', 400),\n\n invalidToken: () => new AuthError('Invalid token', 'INVALID_TOKEN', 401),\n\n tokenExpired: () => new AuthError('Token has expired', 'TOKEN_EXPIRED', 401),\n\n networkError: (message = 'Network request failed') =>\n new AuthError(message, 'NETWORK_ERROR'),\n\n serverError: (message = 'Server error', statusCode = 500) =>\n new AuthError(message, 'SERVER_ERROR', statusCode),\n\n unauthorized: () => new AuthError('Unauthorized', 'UNAUTHORIZED', 401),\n\n notAuthenticated: () => new AuthError('User is not authenticated', 'NOT_AUTHENTICATED'),\n\n storageError: (message = 'Storage operation failed') =>\n new AuthError(message, 'STORAGE_ERROR'),\n\n unknown: (message = 'An unknown error occurred') =>\n new AuthError(message, 'UNKNOWN_ERROR'),\n};\n\n/**\n * Parse error response from API\n */\nexport function parseApiError(response: Response, body: unknown): AuthError {\n const statusCode = response.status;\n\n // Try to extract error message from response body\n let message = response.statusText || 'Request failed';\n if (typeof body === 'object' && body !== null) {\n const errorBody = body as { error?: string; message?: string };\n message = errorBody.error || errorBody.message || message;\n } else if (typeof body === 'string') {\n message = body;\n }\n\n // Map status codes to error codes\n let code: AuthErrorCode;\n switch (statusCode) {\n case 400:\n // Could be invalid email, invalid OTP, etc. - use generic for now\n code = 'INVALID_TOKEN';\n break;\n case 401:\n code = 'UNAUTHORIZED';\n break;\n case 403:\n code = 'UNAUTHORIZED';\n break;\n case 404:\n code = 'SERVER_ERROR';\n break;\n default:\n code = statusCode >= 500 ? 'SERVER_ERROR' : 'UNKNOWN_ERROR';\n }\n\n return new AuthError(message, code, statusCode);\n}\n","import { AuthError } from './types';\n\nconst TOKEN_KEYS = {\n ACCESS_TOKEN: 'cohost_auth_access_token',\n REFRESH_TOKEN: 'cohost_auth_refresh_token',\n TOKEN_EXPIRY: 'cohost_auth_token_expiry',\n USER: 'cohost_auth_user',\n} as const;\n\n/**\n * Storage abstraction interface for token persistence\n */\nexport interface TokenStorage {\n getAccessToken(): string | null;\n setAccessToken(token: string): void;\n getRefreshToken(): string | null;\n setRefreshToken(token: string): void;\n getTokenExpiry(): number | null;\n setTokenExpiry(expiry: number): void;\n getUser<T>(): T | null;\n setUser<T>(user: T): void;\n clear(): void;\n}\n\n/**\n * Check if we're in a browser environment\n */\nfunction isBrowser(): boolean {\n return typeof window !== 'undefined' && typeof window.localStorage !== 'undefined';\n}\n\n/**\n * Web storage implementation (localStorage/sessionStorage)\n */\nclass WebStorage implements TokenStorage {\n private storage: Storage;\n\n constructor(type: 'localStorage' | 'sessionStorage') {\n if (!isBrowser()) {\n throw new AuthError(\n 'Web storage is not available in this environment',\n 'STORAGE_ERROR'\n );\n }\n this.storage = type === 'localStorage' ? window.localStorage : window.sessionStorage;\n }\n\n getAccessToken(): string | null {\n try {\n return this.storage.getItem(TOKEN_KEYS.ACCESS_TOKEN);\n } catch {\n return null;\n }\n }\n\n setAccessToken(token: string): void {\n try {\n this.storage.setItem(TOKEN_KEYS.ACCESS_TOKEN, token);\n } catch (error) {\n throw new AuthError('Failed to save access token', 'STORAGE_ERROR');\n }\n }\n\n getRefreshToken(): string | null {\n try {\n return this.storage.getItem(TOKEN_KEYS.REFRESH_TOKEN);\n } catch {\n return null;\n }\n }\n\n setRefreshToken(token: string): void {\n try {\n this.storage.setItem(TOKEN_KEYS.REFRESH_TOKEN, token);\n } catch (error) {\n throw new AuthError('Failed to save refresh token', 'STORAGE_ERROR');\n }\n }\n\n getTokenExpiry(): number | null {\n try {\n const expiry = this.storage.getItem(TOKEN_KEYS.TOKEN_EXPIRY);\n return expiry ? parseInt(expiry, 10) : null;\n } catch {\n return null;\n }\n }\n\n setTokenExpiry(expiry: number): void {\n try {\n this.storage.setItem(TOKEN_KEYS.TOKEN_EXPIRY, expiry.toString());\n } catch (error) {\n throw new AuthError('Failed to save token expiry', 'STORAGE_ERROR');\n }\n }\n\n getUser<T>(): T | null {\n try {\n const user = this.storage.getItem(TOKEN_KEYS.USER);\n return user ? JSON.parse(user) : null;\n } catch {\n return null;\n }\n }\n\n setUser<T>(user: T): void {\n try {\n this.storage.setItem(TOKEN_KEYS.USER, JSON.stringify(user));\n } catch (error) {\n throw new AuthError('Failed to save user', 'STORAGE_ERROR');\n }\n }\n\n clear(): void {\n try {\n this.storage.removeItem(TOKEN_KEYS.ACCESS_TOKEN);\n this.storage.removeItem(TOKEN_KEYS.REFRESH_TOKEN);\n this.storage.removeItem(TOKEN_KEYS.TOKEN_EXPIRY);\n this.storage.removeItem(TOKEN_KEYS.USER);\n } catch {\n // Silently fail on clear errors\n }\n }\n}\n\n/**\n * In-memory storage implementation (for SSR or non-browser environments)\n */\nclass MemoryStorage implements TokenStorage {\n private accessToken: string | null = null;\n private refreshToken: string | null = null;\n private tokenExpiry: number | null = null;\n private user: unknown = null;\n\n getAccessToken(): string | null {\n return this.accessToken;\n }\n\n setAccessToken(token: string): void {\n this.accessToken = token;\n }\n\n getRefreshToken(): string | null {\n return this.refreshToken;\n }\n\n setRefreshToken(token: string): void {\n this.refreshToken = token;\n }\n\n getTokenExpiry(): number | null {\n return this.tokenExpiry;\n }\n\n setTokenExpiry(expiry: number): void {\n this.tokenExpiry = expiry;\n }\n\n getUser<T>(): T | null {\n return this.user as T | null;\n }\n\n setUser<T>(user: T): void {\n this.user = user;\n }\n\n clear(): void {\n this.accessToken = null;\n this.refreshToken = null;\n this.tokenExpiry = null;\n this.user = null;\n }\n}\n\n/**\n * Create a storage instance based on type\n */\nexport function createStorage(type: 'localStorage' | 'sessionStorage' | 'memory'): TokenStorage {\n if (type === 'memory' || !isBrowser()) {\n return new MemoryStorage();\n }\n return new WebStorage(type);\n}\n\nexport { MemoryStorage, WebStorage };\n","import {\n AuthResult,\n AuthUser,\n TokenPair,\n TokenValidateResult,\n OTPRequestInput,\n OTPVerifyInput,\n TokenRefreshInput,\n TokenValidateInput,\n} from './types';\nimport { parseApiError, authErrors } from './errors';\n\n/**\n * API response wrapper\n */\ninterface ApiResponse<T> {\n status: 'ok' | 'error';\n data: T;\n}\n\n/**\n * Options for API requests\n */\ninterface RequestOptions {\n method?: 'GET' | 'POST' | 'PUT' | 'DELETE';\n body?: unknown;\n headers?: Record<string, string>;\n token?: string;\n}\n\n/**\n * Auth API client for making requests to auth endpoints\n */\nexport class AuthApi {\n private baseUrl: string;\n private debug: boolean;\n\n constructor(baseUrl: string, debug = false) {\n // Remove trailing slash if present\n this.baseUrl = baseUrl.replace(/\\/$/, '');\n this.debug = debug;\n }\n\n /**\n * Make an authenticated or unauthenticated request\n */\n private async request<T>(path: string, options: RequestOptions = {}): Promise<T> {\n const { method = 'GET', body, headers = {}, token } = options;\n\n const url = `${this.baseUrl}${path}`;\n\n const reqHeaders: Record<string, string> = {\n 'Content-Type': 'application/json',\n ...headers,\n };\n\n if (token) {\n reqHeaders['Authorization'] = `Bearer ${token}`;\n }\n\n if (this.debug) {\n console.log(`[AuthClient] ${method} ${url}`);\n if (body) {\n console.log('[AuthClient] Body:', JSON.stringify(body));\n }\n }\n\n let response: Response;\n try {\n response = await fetch(url, {\n method,\n headers: reqHeaders,\n body: body ? JSON.stringify(body) : undefined,\n });\n } catch (error) {\n throw authErrors.networkError(\n error instanceof Error ? error.message : 'Network request failed'\n );\n }\n\n const isJson = response.headers.get('content-type')?.includes('application/json');\n const responseBody = isJson ? await response.json() : await response.text();\n\n if (this.debug) {\n console.log(`[AuthClient] Response (${response.status}):`, responseBody);\n }\n\n if (!response.ok) {\n throw parseApiError(response, responseBody);\n }\n\n // Unwrap API response format { status: 'ok', data: ... }\n if (\n typeof responseBody === 'object' &&\n responseBody !== null &&\n (responseBody as ApiResponse<T>).status === 'ok' &&\n 'data' in responseBody\n ) {\n return (responseBody as ApiResponse<T>).data;\n }\n\n return responseBody as T;\n }\n\n // === OTP Methods ===\n\n /**\n * Request OTP code to be sent to contact (email or phone)\n */\n async requestOTP(input: OTPRequestInput): Promise<{ sent: boolean }> {\n return this.request('/otp/request', {\n method: 'POST',\n body: input,\n });\n }\n\n /**\n * Verify OTP code and get auth result\n */\n async verifyOTP(input: OTPVerifyInput): Promise<AuthResult> {\n return this.request('/otp/verify', {\n method: 'POST',\n body: input,\n });\n }\n\n // === Token Methods ===\n\n /**\n * Refresh token pair using refresh token\n */\n async refreshToken(input: TokenRefreshInput): Promise<TokenPair> {\n return this.request('/token/refresh', {\n method: 'POST',\n body: input,\n });\n }\n\n /**\n * Validate access token\n */\n async validateToken(input: TokenValidateInput): Promise<TokenValidateResult> {\n return this.request('/token/validate', {\n method: 'POST',\n body: input,\n });\n }\n\n /**\n * Revoke token (sign out)\n */\n async revokeToken(token: string): Promise<{ revoked: boolean }> {\n return this.request('/token/revoke', {\n method: 'POST',\n token,\n });\n }\n\n // === User Methods ===\n\n /**\n * Get current authenticated user\n */\n async getCurrentUser(token: string): Promise<{ user: AuthUser; channelId?: string }> {\n return this.request('/me', {\n method: 'GET',\n token,\n });\n }\n}\n","import {\n AuthConfig,\n AuthState,\n AuthUser,\n AuthStateListener,\n Unsubscribe,\n AuthError,\n OTPRequestInput,\n OTPVerifyInput,\n OTPType,\n SetAuthenticatedInput,\n TokenAuthResult,\n} from './types';\nimport { authErrors } from './errors';\nimport { createStorage, TokenStorage } from './storage';\nimport { AuthApi } from './api';\n\nconst DEFAULT_REFRESH_THRESHOLD = 300; // 5 minutes in seconds\n\n/**\n * Main auth client class for managing authentication state\n */\nexport class AuthClient {\n private config: Required<Omit<AuthConfig, 'channelId' | 'tokenParam'>> & { channelId?: string; tokenParam?: string };\n private storage: TokenStorage;\n private api: AuthApi;\n private state: AuthState;\n private listeners: Set<AuthStateListener> = new Set();\n private refreshTimer: ReturnType<typeof setTimeout> | null = null;\n private initialized = false;\n\n constructor(config: AuthConfig) {\n this.config = {\n apiUrl: config.apiUrl,\n channelId: config.channelId,\n tokenParam: config.tokenParam,\n storage: config.storage ?? 'localStorage',\n debug: config.debug ?? false,\n autoRefresh: config.autoRefresh ?? true,\n refreshThreshold: config.refreshThreshold ?? DEFAULT_REFRESH_THRESHOLD,\n };\n\n this.storage = createStorage(this.config.storage);\n this.api = new AuthApi(this.config.apiUrl, this.config.debug);\n\n // Initialize state\n this.state = {\n isAuthenticated: false,\n isLoading: true,\n user: null,\n accessToken: null,\n error: null,\n };\n }\n\n /**\n * Initialize the auth client by loading saved state\n */\n async initialize(): Promise<void> {\n if (this.initialized) {\n return;\n }\n\n this.debug('Initializing auth client');\n\n try {\n const accessToken = this.storage.getAccessToken();\n const user = this.storage.getUser<AuthUser>();\n const expiry = this.storage.getTokenExpiry();\n\n if (accessToken && user && expiry) {\n // Check if token is expired\n const now = Math.floor(Date.now() / 1000);\n if (expiry > now) {\n // Token is valid, restore state\n this.updateState({\n isAuthenticated: true,\n isLoading: false,\n user,\n accessToken,\n error: null,\n });\n\n // Set up auto-refresh if enabled\n if (this.config.autoRefresh) {\n this.scheduleRefresh(expiry - now);\n }\n\n this.initialized = true;\n return;\n }\n\n // Token expired, try to refresh\n const refreshToken = this.storage.getRefreshToken();\n if (refreshToken) {\n await this.performRefresh(refreshToken);\n this.initialized = true;\n return;\n }\n }\n\n // No valid session, clear and set as not authenticated\n this.storage.clear();\n this.updateState({\n isAuthenticated: false,\n isLoading: false,\n user: null,\n accessToken: null,\n error: null,\n });\n } catch (error) {\n this.debug('Initialization error:', error);\n this.storage.clear();\n this.updateState({\n isAuthenticated: false,\n isLoading: false,\n user: null,\n accessToken: null,\n error: AuthError.fromError(error as Error),\n });\n }\n\n this.initialized = true;\n }\n\n // === Public API ===\n\n /**\n * Get current auth state\n */\n getState(): AuthState {\n return { ...this.state };\n }\n\n /**\n * Subscribe to auth state changes\n */\n onAuthStateChanged(listener: AuthStateListener): Unsubscribe {\n this.listeners.add(listener);\n // Immediately call with current state\n listener(this.getState());\n return () => {\n this.listeners.delete(listener);\n };\n }\n\n /**\n * Check if user is authenticated\n */\n get isAuthenticated(): boolean {\n return this.state.isAuthenticated;\n }\n\n /**\n * Get current user\n */\n get currentUser(): AuthUser | null {\n return this.state.user;\n }\n\n /**\n * Get current access token\n */\n get accessToken(): string | null {\n return this.state.accessToken;\n }\n\n // === OTP Authentication ===\n\n /**\n * Request OTP code to be sent to contact (email or phone)\n * @param contact - Email address or phone number\n * @param type - Type of contact ('email' or 'phone')\n */\n async requestOTP(contact: string, type: OTPType = 'email'): Promise<boolean> {\n this.debug('Requesting OTP for:', contact, type);\n\n const input: OTPRequestInput = {\n contact,\n type,\n channelId: this.config.channelId,\n };\n\n const result = await this.api.requestOTP(input);\n return result.sent;\n }\n\n /**\n * Verify OTP code and sign in\n * @param contact - Email address or phone number that received the OTP\n * @param code - OTP code to verify\n */\n async verifyOTP(contact: string, code: string): Promise<AuthUser> {\n this.debug('Verifying OTP for:', contact);\n\n const input: OTPVerifyInput = {\n contact,\n code,\n channelId: this.config.channelId,\n };\n\n const result = await this.api.verifyOTP(input);\n\n // The customToken from verifyOTP is a JWT that we use as our access token\n // We need to also get a refresh token by calling refresh endpoint\n // For now, we'll store the customToken as access token\n // TODO: Backend should return both access and refresh tokens\n\n // Store tokens and user\n this.storage.setAccessToken(result.customToken);\n this.storage.setUser(result.user);\n\n // Set expiry (assume 7 days if not provided)\n const expiry = Math.floor(Date.now() / 1000) + 7 * 24 * 60 * 60;\n this.storage.setTokenExpiry(expiry);\n\n this.updateState({\n isAuthenticated: true,\n isLoading: false,\n user: result.user,\n accessToken: result.customToken,\n error: null,\n });\n\n if (this.config.autoRefresh) {\n this.scheduleRefresh(7 * 24 * 60 * 60);\n }\n\n return result.user;\n }\n\n // === Custom Auth Flow ===\n\n /**\n * Manually set authenticated state after a custom auth flow (e.g., passkey)\n * Use this when you handle authentication outside the standard OTP flow\n */\n setAuthenticated(input: SetAuthenticatedInput): void {\n this.debug('Setting authenticated state for:', input.user.uid);\n\n const { accessToken, user, refreshToken, expiresIn = 7 * 24 * 60 * 60 } = input;\n\n // Store tokens and user\n this.storage.setAccessToken(accessToken);\n this.storage.setUser(user);\n\n if (refreshToken) {\n this.storage.setRefreshToken(refreshToken);\n }\n\n const expiry = Math.floor(Date.now() / 1000) + expiresIn;\n this.storage.setTokenExpiry(expiry);\n\n this.updateState({\n isAuthenticated: true,\n isLoading: false,\n user,\n accessToken,\n error: null,\n });\n\n if (this.config.autoRefresh && refreshToken) {\n this.scheduleRefresh(expiresIn);\n }\n }\n\n /**\n * Get the configured token param name (if any)\n * Returns undefined if token param detection is disabled\n */\n get tokenParamName(): string | undefined {\n return this.config.tokenParam;\n }\n\n /**\n * Authenticate using a token (e.g., from URL query param).\n * Validates the token via API and sets auth state if valid.\n * @param token - The token to authenticate with\n * @returns Result indicating success/failure\n */\n async authenticateWithToken(token: string): Promise<TokenAuthResult> {\n this.debug('Authenticating with token');\n\n // Set loading state while authenticating\n this.updateState({\n ...this.state,\n isLoading: true,\n error: null,\n });\n\n try {\n // Validate the token via API\n const validateResult = await this.api.validateToken({ accessToken: token });\n\n if (!validateResult.valid || !validateResult.uid) {\n this.debug('Token validation failed: invalid token');\n this.updateState({\n ...this.state,\n isLoading: false,\n });\n return { success: false, error: 'Invalid token' };\n }\n\n // Get user info from the token\n const userResult = await this.api.getCurrentUser(token);\n\n // Calculate expiry from token\n const now = Math.floor(Date.now() / 1000);\n const expiresIn = validateResult.exp ? validateResult.exp - now : 7 * 24 * 60 * 60;\n\n // Set authenticated state (this also sets isLoading: false)\n this.setAuthenticated({\n accessToken: token,\n user: userResult.user,\n expiresIn,\n });\n\n this.debug('Token authentication successful for:', userResult.user.uid);\n\n return { success: true, user: userResult.user };\n } catch (error) {\n this.debug('Token authentication failed:', error);\n this.updateState({\n ...this.state,\n isLoading: false,\n error: AuthError.fromError(error as Error, 'INVALID_TOKEN'),\n });\n const message = error instanceof Error ? error.message : 'Token authentication failed';\n return { success: false, error: message };\n }\n }\n\n // === Token Management ===\n\n /**\n * Get current access token, refreshing if needed\n */\n async getToken(): Promise<string | null> {\n if (!this.state.accessToken) {\n return null;\n }\n\n // Check if token needs refresh\n const expiry = this.storage.getTokenExpiry();\n const now = Math.floor(Date.now() / 1000);\n\n if (expiry && expiry - now < this.config.refreshThreshold) {\n const refreshToken = this.storage.getRefreshToken();\n if (refreshToken) {\n await this.performRefresh(refreshToken);\n }\n }\n\n return this.state.accessToken;\n }\n\n /**\n * Manually refresh the token\n */\n async refreshToken(): Promise<void> {\n const refreshToken = this.storage.getRefreshToken();\n if (!refreshToken) {\n throw authErrors.notAuthenticated();\n }\n await this.performRefresh(refreshToken);\n }\n\n /**\n * Sign out and clear all tokens\n */\n async signOut(): Promise<void> {\n this.debug('Signing out');\n\n // Cancel any pending refresh\n if (this.refreshTimer) {\n clearTimeout(this.refreshTimer);\n this.refreshTimer = null;\n }\n\n // Try to revoke token on server (best effort)\n if (this.state.accessToken) {\n try {\n await this.api.revokeToken(this.state.accessToken);\n } catch (error) {\n this.debug('Revoke token error (ignored):', error);\n }\n }\n\n // Clear storage\n this.storage.clear();\n\n // Update state\n this.updateState({\n isAuthenticated: false,\n isLoading: false,\n user: null,\n accessToken: null,\n error: null,\n });\n }\n\n // === User ===\n\n /**\n * Get current user from server\n */\n async getCurrentUser(): Promise<AuthUser | null> {\n if (!this.state.accessToken) {\n return null;\n }\n\n const result = await this.api.getCurrentUser(this.state.accessToken);\n\n // Update stored user\n this.storage.setUser(result.user);\n this.updateState({\n ...this.state,\n user: result.user,\n });\n\n return result.user;\n }\n\n // === Private Methods ===\n\n private updateState(newState: AuthState): void {\n this.state = newState;\n // Notify all listeners\n for (const listener of this.listeners) {\n try {\n listener(this.getState());\n } catch (error) {\n this.debug('Listener error:', error);\n }\n }\n }\n\n private async performRefresh(refreshToken: string): Promise<void> {\n this.debug('Refreshing token');\n\n try {\n const result = await this.api.refreshToken({\n refreshToken,\n channelId: this.config.channelId,\n });\n\n // Store new tokens\n this.storage.setAccessToken(result.accessToken);\n this.storage.setRefreshToken(result.refreshToken);\n\n const expiry = Math.floor(Date.now() / 1000) + result.expiresIn;\n this.storage.setTokenExpiry(expiry);\n\n // Update state with new token\n this.updateState({\n ...this.state,\n accessToken: result.accessToken,\n error: null,\n });\n\n // Schedule next refresh\n if (this.config.autoRefresh) {\n this.scheduleRefresh(result.expiresIn);\n }\n } catch (error) {\n this.debug('Refresh failed:', error);\n // On refresh failure, sign out\n this.storage.clear();\n this.updateState({\n isAuthenticated: false,\n isLoading: false,\n user: null,\n accessToken: null,\n error: AuthError.fromError(error as Error, 'TOKEN_EXPIRED'),\n });\n }\n }\n\n private scheduleRefresh(expiresIn: number): void {\n if (this.refreshTimer) {\n clearTimeout(this.refreshTimer);\n }\n\n // Refresh when threshold is reached\n const refreshIn = Math.max(0, expiresIn - this.config.refreshThreshold) * 1000;\n\n this.debug(`Scheduling refresh in ${refreshIn / 1000}s`);\n\n this.refreshTimer = setTimeout(() => {\n const refreshToken = this.storage.getRefreshToken();\n if (refreshToken) {\n this.performRefresh(refreshToken);\n }\n }, refreshIn);\n }\n\n private debug(...args: unknown[]): void {\n if (this.config.debug) {\n console.log('[AuthClient]', ...args);\n }\n }\n}\n"],"mappings":"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","names":["index_exports","__export","AuthApi","AuthClient","AuthError","authErrors","createAuthClient","createStorage","__toCommonJS","AuthError","_AuthError","message","code","statusCode","originalError","__publicField","error","authErrors","AuthError","message","statusCode","parseApiError","response","body","errorBody","code","TOKEN_KEYS","isBrowser","WebStorage","type","__publicField","AuthError","token","expiry","user","MemoryStorage","createStorage","AuthApi","baseUrl","debug","__publicField","path","options","method","body","headers","token","url","reqHeaders","response","error","authErrors","responseBody","parseApiError","input","DEFAULT_REFRESH_THRESHOLD","AuthClient","config","__publicField","createStorage","AuthApi","accessToken","user","expiry","now","refreshToken","error","AuthError","listener","contact","type","input","code","result","expiresIn","token","validateResult","userResult","authErrors","newState","refreshIn","args","createAuthClient","config","AuthClient"]}
|
package/dist/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var O=Object.defineProperty;var I=(s,e,t)=>e in s?O(s,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):s[e]=t;var i=(s,e,t)=>I(s,typeof e!="symbol"?e+"":e,t);var o=class s extends Error{constructor(t,r,n,a){super(t);i(this,"code");i(this,"statusCode");i(this,"originalError");this.name="AuthError",this.code=r,this.statusCode=n,this.originalError=a}static fromError(t,r="UNKNOWN_ERROR"){return t instanceof s?t:new s(t.message,r,void 0,t)}};var c={invalidEmail:()=>new o("Invalid email address","INVALID_EMAIL",400),invalidOTP:()=>new o("Invalid or incorrect OTP code","INVALID_OTP",400),otpExpired:()=>new o("OTP code has expired","OTP_EXPIRED",400),invalidToken:()=>new o("Invalid token","INVALID_TOKEN",401),tokenExpired:()=>new o("Token has expired","TOKEN_EXPIRED",401),networkError:(s="Network request failed")=>new o(s,"NETWORK_ERROR"),serverError:(s="Server error",e=500)=>new o(s,"SERVER_ERROR",e),unauthorized:()=>new o("Unauthorized","UNAUTHORIZED",401),notAuthenticated:()=>new o("User is not authenticated","NOT_AUTHENTICATED"),storageError:(s="Storage operation failed")=>new o(s,"STORAGE_ERROR"),unknown:(s="An unknown error occurred")=>new o(s,"UNKNOWN_ERROR")};function A(s,e){let t=s.status,r=s.statusText||"Request failed";if(typeof e=="object"&&e!==null){let a=e;r=a.error||a.message||r}else typeof e=="string"&&(r=e);let n;switch(t){case 400:n="INVALID_TOKEN";break;case 401:n="UNAUTHORIZED";break;case 403:n="UNAUTHORIZED";break;case 404:n="SERVER_ERROR";break;default:n=t>=500?"SERVER_ERROR":"UNKNOWN_ERROR"}return new o(r,n,t)}var u={ACCESS_TOKEN:"cohost_auth_access_token",REFRESH_TOKEN:"cohost_auth_refresh_token",TOKEN_EXPIRY:"cohost_auth_token_expiry",USER:"cohost_auth_user"};function y(){return typeof window<"u"&&typeof window.localStorage<"u"}var f=class{constructor(e){i(this,"storage");if(!y())throw new o("Web storage is not available in this environment","STORAGE_ERROR");this.storage=e==="localStorage"?window.localStorage:window.sessionStorage}getAccessToken(){try{return this.storage.getItem(u.ACCESS_TOKEN)}catch{return null}}setAccessToken(e){try{this.storage.setItem(u.ACCESS_TOKEN,e)}catch{throw new o("Failed to save access token","STORAGE_ERROR")}}getRefreshToken(){try{return this.storage.getItem(u.REFRESH_TOKEN)}catch{return null}}setRefreshToken(e){try{this.storage.setItem(u.REFRESH_TOKEN,e)}catch{throw new o("Failed to save refresh token","STORAGE_ERROR")}}getTokenExpiry(){try{let e=this.storage.getItem(u.TOKEN_EXPIRY);return e?parseInt(e,10):null}catch{return null}}setTokenExpiry(e){try{this.storage.setItem(u.TOKEN_EXPIRY,e.toString())}catch{throw new o("Failed to save token expiry","STORAGE_ERROR")}}getUser(){try{let e=this.storage.getItem(u.USER);return e?JSON.parse(e):null}catch{return null}}setUser(e){try{this.storage.setItem(u.USER,JSON.stringify(e))}catch{throw new o("Failed to save user","STORAGE_ERROR")}}clear(){try{this.storage.removeItem(u.ACCESS_TOKEN),this.storage.removeItem(u.REFRESH_TOKEN),this.storage.removeItem(u.TOKEN_EXPIRY),this.storage.removeItem(u.USER)}catch{}}},p=class{constructor(){i(this,"accessToken",null);i(this,"refreshToken",null);i(this,"tokenExpiry",null);i(this,"user",null)}getAccessToken(){return this.accessToken}setAccessToken(e){this.accessToken=e}getRefreshToken(){return this.refreshToken}setRefreshToken(e){this.refreshToken=e}getTokenExpiry(){return this.tokenExpiry}setTokenExpiry(e){this.tokenExpiry=e}getUser(){return this.user}setUser(e){this.user=e}clear(){this.accessToken=null,this.refreshToken=null,this.tokenExpiry=null,this.user=null}};function R(s){return s==="memory"||!y()?new p:new f(s)}var T=class{constructor(e,t=!1){i(this,"baseUrl");i(this,"debug");this.baseUrl=e.replace(/\/$/,""),this.debug=t}async request(e,t={}){let{method:r="GET",body:n,headers:a={},token:d}=t,E=`${this.baseUrl}${e}`,k={"Content-Type":"application/json",...a};d&&(k.Authorization=`Bearer ${d}`),this.debug&&(console.log(`[AuthClient] ${r} ${E}`),n&&console.log("[AuthClient] Body:",JSON.stringify(n)));let l;try{l=await fetch(E,{method:r,headers:k,body:n?JSON.stringify(n):void 0})}catch(m){throw c.networkError(m instanceof Error?m.message:"Network request failed")}let h=l.headers.get("content-type")?.includes("application/json")?await l.json():await l.text();if(this.debug&&console.log(`[AuthClient] Response (${l.status}):`,h),!l.ok)throw A(l,h);return typeof h=="object"&&h!==null&&h.status==="ok"&&"data"in h?h.data:h}async requestOTP(e){return this.request("/otp/request",{method:"POST",body:e})}async verifyOTP(e){return this.request("/otp/verify",{method:"POST",body:e})}async refreshToken(e){return this.request("/token/refresh",{method:"POST",body:e})}async validateToken(e){return this.request("/token/validate",{method:"POST",body:e})}async revokeToken(e){return this.request("/token/revoke",{method:"POST",token:e})}async getCurrentUser(e){return this.request("/me",{method:"GET",token:e})}};var S=300,g=class{constructor(e){i(this,"config");i(this,"storage");i(this,"api");i(this,"state");i(this,"listeners",new Set);i(this,"refreshTimer",null);i(this,"initialized",!1);this.config={apiUrl:e.apiUrl,channelId:e.channelId,storage:e.storage??"localStorage",debug:e.debug??!1,autoRefresh:e.autoRefresh??!0,refreshThreshold:e.refreshThreshold??S},this.storage=R(this.config.storage),this.api=new T(this.config.apiUrl,this.config.debug),this.state={isAuthenticated:!1,isLoading:!0,user:null,accessToken:null,error:null}}async initialize(){if(!this.initialized){this.debug("Initializing auth client");try{let e=this.storage.getAccessToken(),t=this.storage.getUser(),r=this.storage.getTokenExpiry();if(e&&t&&r){let n=Math.floor(Date.now()/1e3);if(r>n){this.updateState({isAuthenticated:!0,isLoading:!1,user:t,accessToken:e,error:null}),this.config.autoRefresh&&this.scheduleRefresh(r-n),this.initialized=!0;return}let a=this.storage.getRefreshToken();if(a){await this.performRefresh(a),this.initialized=!0;return}}this.storage.clear(),this.updateState({isAuthenticated:!1,isLoading:!1,user:null,accessToken:null,error:null})}catch(e){this.debug("Initialization error:",e),this.storage.clear(),this.updateState({isAuthenticated:!1,isLoading:!1,user:null,accessToken:null,error:o.fromError(e)})}this.initialized=!0}}getState(){return{...this.state}}onAuthStateChanged(e){return this.listeners.add(e),e(this.getState()),()=>{this.listeners.delete(e)}}get isAuthenticated(){return this.state.isAuthenticated}get currentUser(){return this.state.user}get accessToken(){return this.state.accessToken}async requestOTP(e,t="email"){this.debug("Requesting OTP for:",e,t);let r={contact:e,type:t,channelId:this.config.channelId};return(await this.api.requestOTP(r)).sent}async verifyOTP(e,t){this.debug("Verifying OTP for:",e);let r={contact:e,code:t,channelId:this.config.channelId},n=await this.api.verifyOTP(r);this.storage.setAccessToken(n.customToken),this.storage.setUser(n.user);let a=Math.floor(Date.now()/1e3)+10080*60;return this.storage.setTokenExpiry(a),this.updateState({isAuthenticated:!0,isLoading:!1,user:n.user,accessToken:n.customToken,error:null}),this.config.autoRefresh&&this.scheduleRefresh(10080*60),n.user}setAuthenticated(e){this.debug("Setting authenticated state for:",e.user.uid);let{accessToken:t,user:r,refreshToken:n,expiresIn:a=10080*60}=e;this.storage.setAccessToken(t),this.storage.setUser(r),n&&this.storage.setRefreshToken(n);let d=Math.floor(Date.now()/1e3)+a;this.storage.setTokenExpiry(d),this.updateState({isAuthenticated:!0,isLoading:!1,user:r,accessToken:t,error:null}),this.config.autoRefresh&&n&&this.scheduleRefresh(a)}async getToken(){if(!this.state.accessToken)return null;let e=this.storage.getTokenExpiry(),t=Math.floor(Date.now()/1e3);if(e&&e-t<this.config.refreshThreshold){let r=this.storage.getRefreshToken();r&&await this.performRefresh(r)}return this.state.accessToken}async refreshToken(){let e=this.storage.getRefreshToken();if(!e)throw c.notAuthenticated();await this.performRefresh(e)}async signOut(){if(this.debug("Signing out"),this.refreshTimer&&(clearTimeout(this.refreshTimer),this.refreshTimer=null),this.state.accessToken)try{await this.api.revokeToken(this.state.accessToken)}catch(e){this.debug("Revoke token error (ignored):",e)}this.storage.clear(),this.updateState({isAuthenticated:!1,isLoading:!1,user:null,accessToken:null,error:null})}async getCurrentUser(){if(!this.state.accessToken)return null;let e=await this.api.getCurrentUser(this.state.accessToken);return this.storage.setUser(e.user),this.updateState({...this.state,user:e.user}),e.user}updateState(e){this.state=e;for(let t of this.listeners)try{t(this.getState())}catch(r){this.debug("Listener error:",r)}}async performRefresh(e){this.debug("Refreshing token");try{let t=await this.api.refreshToken({refreshToken:e,channelId:this.config.channelId});this.storage.setAccessToken(t.accessToken),this.storage.setRefreshToken(t.refreshToken);let r=Math.floor(Date.now()/1e3)+t.expiresIn;this.storage.setTokenExpiry(r),this.updateState({...this.state,accessToken:t.accessToken,error:null}),this.config.autoRefresh&&this.scheduleRefresh(t.expiresIn)}catch(t){this.debug("Refresh failed:",t),this.storage.clear(),this.updateState({isAuthenticated:!1,isLoading:!1,user:null,accessToken:null,error:o.fromError(t,"TOKEN_EXPIRED")})}}scheduleRefresh(e){this.refreshTimer&&clearTimeout(this.refreshTimer);let t=Math.max(0,e-this.config.refreshThreshold)*1e3;this.debug(`Scheduling refresh in ${t/1e3}s`),this.refreshTimer=setTimeout(()=>{let r=this.storage.getRefreshToken();r&&this.performRefresh(r)},t)}debug(...e){this.config.debug&&console.log("[AuthClient]",...e)}};function re(s){return new g(s)}export{T as AuthApi,g as AuthClient,o as AuthError,c as authErrors,re as createAuthClient,R as createStorage};
|
|
1
|
+
var O=Object.defineProperty;var I=(n,e,t)=>e in n?O(n,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):n[e]=t;var i=(n,e,t)=>I(n,typeof e!="symbol"?e+"":e,t);var o=class n extends Error{constructor(t,r,s,a){super(t);i(this,"code");i(this,"statusCode");i(this,"originalError");this.name="AuthError",this.code=r,this.statusCode=s,this.originalError=a}static fromError(t,r="UNKNOWN_ERROR"){return t instanceof n?t:new n(t.message,r,void 0,t)}};var l={invalidEmail:()=>new o("Invalid email address","INVALID_EMAIL",400),invalidOTP:()=>new o("Invalid or incorrect OTP code","INVALID_OTP",400),otpExpired:()=>new o("OTP code has expired","OTP_EXPIRED",400),invalidToken:()=>new o("Invalid token","INVALID_TOKEN",401),tokenExpired:()=>new o("Token has expired","TOKEN_EXPIRED",401),networkError:(n="Network request failed")=>new o(n,"NETWORK_ERROR"),serverError:(n="Server error",e=500)=>new o(n,"SERVER_ERROR",e),unauthorized:()=>new o("Unauthorized","UNAUTHORIZED",401),notAuthenticated:()=>new o("User is not authenticated","NOT_AUTHENTICATED"),storageError:(n="Storage operation failed")=>new o(n,"STORAGE_ERROR"),unknown:(n="An unknown error occurred")=>new o(n,"UNKNOWN_ERROR")};function A(n,e){let t=n.status,r=n.statusText||"Request failed";if(typeof e=="object"&&e!==null){let a=e;r=a.error||a.message||r}else typeof e=="string"&&(r=e);let s;switch(t){case 400:s="INVALID_TOKEN";break;case 401:s="UNAUTHORIZED";break;case 403:s="UNAUTHORIZED";break;case 404:s="SERVER_ERROR";break;default:s=t>=500?"SERVER_ERROR":"UNKNOWN_ERROR"}return new o(r,s,t)}var u={ACCESS_TOKEN:"cohost_auth_access_token",REFRESH_TOKEN:"cohost_auth_refresh_token",TOKEN_EXPIRY:"cohost_auth_token_expiry",USER:"cohost_auth_user"};function y(){return typeof window<"u"&&typeof window.localStorage<"u"}var f=class{constructor(e){i(this,"storage");if(!y())throw new o("Web storage is not available in this environment","STORAGE_ERROR");this.storage=e==="localStorage"?window.localStorage:window.sessionStorage}getAccessToken(){try{return this.storage.getItem(u.ACCESS_TOKEN)}catch{return null}}setAccessToken(e){try{this.storage.setItem(u.ACCESS_TOKEN,e)}catch{throw new o("Failed to save access token","STORAGE_ERROR")}}getRefreshToken(){try{return this.storage.getItem(u.REFRESH_TOKEN)}catch{return null}}setRefreshToken(e){try{this.storage.setItem(u.REFRESH_TOKEN,e)}catch{throw new o("Failed to save refresh token","STORAGE_ERROR")}}getTokenExpiry(){try{let e=this.storage.getItem(u.TOKEN_EXPIRY);return e?parseInt(e,10):null}catch{return null}}setTokenExpiry(e){try{this.storage.setItem(u.TOKEN_EXPIRY,e.toString())}catch{throw new o("Failed to save token expiry","STORAGE_ERROR")}}getUser(){try{let e=this.storage.getItem(u.USER);return e?JSON.parse(e):null}catch{return null}}setUser(e){try{this.storage.setItem(u.USER,JSON.stringify(e))}catch{throw new o("Failed to save user","STORAGE_ERROR")}}clear(){try{this.storage.removeItem(u.ACCESS_TOKEN),this.storage.removeItem(u.REFRESH_TOKEN),this.storage.removeItem(u.TOKEN_EXPIRY),this.storage.removeItem(u.USER)}catch{}}},p=class{constructor(){i(this,"accessToken",null);i(this,"refreshToken",null);i(this,"tokenExpiry",null);i(this,"user",null)}getAccessToken(){return this.accessToken}setAccessToken(e){this.accessToken=e}getRefreshToken(){return this.refreshToken}setRefreshToken(e){this.refreshToken=e}getTokenExpiry(){return this.tokenExpiry}setTokenExpiry(e){this.tokenExpiry=e}getUser(){return this.user}setUser(e){this.user=e}clear(){this.accessToken=null,this.refreshToken=null,this.tokenExpiry=null,this.user=null}};function k(n){return n==="memory"||!y()?new p:new f(n)}var g=class{constructor(e,t=!1){i(this,"baseUrl");i(this,"debug");this.baseUrl=e.replace(/\/$/,""),this.debug=t}async request(e,t={}){let{method:r="GET",body:s,headers:a={},token:d}=t,R=`${this.baseUrl}${e}`,E={"Content-Type":"application/json",...a};d&&(E.Authorization=`Bearer ${d}`),this.debug&&(console.log(`[AuthClient] ${r} ${R}`),s&&console.log("[AuthClient] Body:",JSON.stringify(s)));let c;try{c=await fetch(R,{method:r,headers:E,body:s?JSON.stringify(s):void 0})}catch(m){throw l.networkError(m instanceof Error?m.message:"Network request failed")}let h=c.headers.get("content-type")?.includes("application/json")?await c.json():await c.text();if(this.debug&&console.log(`[AuthClient] Response (${c.status}):`,h),!c.ok)throw A(c,h);return typeof h=="object"&&h!==null&&h.status==="ok"&&"data"in h?h.data:h}async requestOTP(e){return this.request("/otp/request",{method:"POST",body:e})}async verifyOTP(e){return this.request("/otp/verify",{method:"POST",body:e})}async refreshToken(e){return this.request("/token/refresh",{method:"POST",body:e})}async validateToken(e){return this.request("/token/validate",{method:"POST",body:e})}async revokeToken(e){return this.request("/token/revoke",{method:"POST",token:e})}async getCurrentUser(e){return this.request("/me",{method:"GET",token:e})}};var S=300,T=class{constructor(e){i(this,"config");i(this,"storage");i(this,"api");i(this,"state");i(this,"listeners",new Set);i(this,"refreshTimer",null);i(this,"initialized",!1);this.config={apiUrl:e.apiUrl,channelId:e.channelId,tokenParam:e.tokenParam,storage:e.storage??"localStorage",debug:e.debug??!1,autoRefresh:e.autoRefresh??!0,refreshThreshold:e.refreshThreshold??S},this.storage=k(this.config.storage),this.api=new g(this.config.apiUrl,this.config.debug),this.state={isAuthenticated:!1,isLoading:!0,user:null,accessToken:null,error:null}}async initialize(){if(!this.initialized){this.debug("Initializing auth client");try{let e=this.storage.getAccessToken(),t=this.storage.getUser(),r=this.storage.getTokenExpiry();if(e&&t&&r){let s=Math.floor(Date.now()/1e3);if(r>s){this.updateState({isAuthenticated:!0,isLoading:!1,user:t,accessToken:e,error:null}),this.config.autoRefresh&&this.scheduleRefresh(r-s),this.initialized=!0;return}let a=this.storage.getRefreshToken();if(a){await this.performRefresh(a),this.initialized=!0;return}}this.storage.clear(),this.updateState({isAuthenticated:!1,isLoading:!1,user:null,accessToken:null,error:null})}catch(e){this.debug("Initialization error:",e),this.storage.clear(),this.updateState({isAuthenticated:!1,isLoading:!1,user:null,accessToken:null,error:o.fromError(e)})}this.initialized=!0}}getState(){return{...this.state}}onAuthStateChanged(e){return this.listeners.add(e),e(this.getState()),()=>{this.listeners.delete(e)}}get isAuthenticated(){return this.state.isAuthenticated}get currentUser(){return this.state.user}get accessToken(){return this.state.accessToken}async requestOTP(e,t="email"){this.debug("Requesting OTP for:",e,t);let r={contact:e,type:t,channelId:this.config.channelId};return(await this.api.requestOTP(r)).sent}async verifyOTP(e,t){this.debug("Verifying OTP for:",e);let r={contact:e,code:t,channelId:this.config.channelId},s=await this.api.verifyOTP(r);this.storage.setAccessToken(s.customToken),this.storage.setUser(s.user);let a=Math.floor(Date.now()/1e3)+10080*60;return this.storage.setTokenExpiry(a),this.updateState({isAuthenticated:!0,isLoading:!1,user:s.user,accessToken:s.customToken,error:null}),this.config.autoRefresh&&this.scheduleRefresh(10080*60),s.user}setAuthenticated(e){this.debug("Setting authenticated state for:",e.user.uid);let{accessToken:t,user:r,refreshToken:s,expiresIn:a=10080*60}=e;this.storage.setAccessToken(t),this.storage.setUser(r),s&&this.storage.setRefreshToken(s);let d=Math.floor(Date.now()/1e3)+a;this.storage.setTokenExpiry(d),this.updateState({isAuthenticated:!0,isLoading:!1,user:r,accessToken:t,error:null}),this.config.autoRefresh&&s&&this.scheduleRefresh(a)}get tokenParamName(){return this.config.tokenParam}async authenticateWithToken(e){this.debug("Authenticating with token"),this.updateState({...this.state,isLoading:!0,error:null});try{let t=await this.api.validateToken({accessToken:e});if(!t.valid||!t.uid)return this.debug("Token validation failed: invalid token"),this.updateState({...this.state,isLoading:!1}),{success:!1,error:"Invalid token"};let r=await this.api.getCurrentUser(e),s=Math.floor(Date.now()/1e3),a=t.exp?t.exp-s:10080*60;return this.setAuthenticated({accessToken:e,user:r.user,expiresIn:a}),this.debug("Token authentication successful for:",r.user.uid),{success:!0,user:r.user}}catch(t){return this.debug("Token authentication failed:",t),this.updateState({...this.state,isLoading:!1,error:o.fromError(t,"INVALID_TOKEN")}),{success:!1,error:t instanceof Error?t.message:"Token authentication failed"}}}async getToken(){if(!this.state.accessToken)return null;let e=this.storage.getTokenExpiry(),t=Math.floor(Date.now()/1e3);if(e&&e-t<this.config.refreshThreshold){let r=this.storage.getRefreshToken();r&&await this.performRefresh(r)}return this.state.accessToken}async refreshToken(){let e=this.storage.getRefreshToken();if(!e)throw l.notAuthenticated();await this.performRefresh(e)}async signOut(){if(this.debug("Signing out"),this.refreshTimer&&(clearTimeout(this.refreshTimer),this.refreshTimer=null),this.state.accessToken)try{await this.api.revokeToken(this.state.accessToken)}catch(e){this.debug("Revoke token error (ignored):",e)}this.storage.clear(),this.updateState({isAuthenticated:!1,isLoading:!1,user:null,accessToken:null,error:null})}async getCurrentUser(){if(!this.state.accessToken)return null;let e=await this.api.getCurrentUser(this.state.accessToken);return this.storage.setUser(e.user),this.updateState({...this.state,user:e.user}),e.user}updateState(e){this.state=e;for(let t of this.listeners)try{t(this.getState())}catch(r){this.debug("Listener error:",r)}}async performRefresh(e){this.debug("Refreshing token");try{let t=await this.api.refreshToken({refreshToken:e,channelId:this.config.channelId});this.storage.setAccessToken(t.accessToken),this.storage.setRefreshToken(t.refreshToken);let r=Math.floor(Date.now()/1e3)+t.expiresIn;this.storage.setTokenExpiry(r),this.updateState({...this.state,accessToken:t.accessToken,error:null}),this.config.autoRefresh&&this.scheduleRefresh(t.expiresIn)}catch(t){this.debug("Refresh failed:",t),this.storage.clear(),this.updateState({isAuthenticated:!1,isLoading:!1,user:null,accessToken:null,error:o.fromError(t,"TOKEN_EXPIRED")})}}scheduleRefresh(e){this.refreshTimer&&clearTimeout(this.refreshTimer);let t=Math.max(0,e-this.config.refreshThreshold)*1e3;this.debug(`Scheduling refresh in ${t/1e3}s`),this.refreshTimer=setTimeout(()=>{let r=this.storage.getRefreshToken();r&&this.performRefresh(r)},t)}debug(...e){this.config.debug&&console.log("[AuthClient]",...e)}};function se(n){return new T(n)}export{g as AuthApi,T as AuthClient,o as AuthError,l as authErrors,se as createAuthClient,k as createStorage};
|
|
2
2
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types.ts","../src/errors.ts","../src/storage.ts","../src/api.ts","../src/client.ts","../src/index.ts"],"sourcesContent":["/**\n * Configuration options for initializing AuthClient\n */\nexport interface AuthConfig {\n /** Base URL for the auth API (e.g., 'https://api.cohost.vip' or '/api') */\n apiUrl: string;\n /** Optional channel ID for multi-tenant scenarios */\n channelId?: string;\n /** Storage type for tokens (default: 'localStorage') */\n storage?: 'localStorage' | 'sessionStorage' | 'memory';\n /** Enable debug logging */\n debug?: boolean;\n /** Auto-refresh tokens before expiry (default: true) */\n autoRefresh?: boolean;\n /** Refresh tokens this many seconds before expiry (default: 300 = 5 minutes) */\n refreshThreshold?: number;\n}\n\n/**\n * User object returned from auth endpoints\n */\nexport interface AuthUser {\n uid: string;\n email: string;\n emailVerified: boolean;\n displayName?: string;\n photoURL?: string;\n phoneNumber?: string;\n provider: string;\n providerId: string;\n}\n\n/**\n * Token pair returned from authentication\n */\nexport interface TokenPair {\n accessToken: string;\n refreshToken: string;\n expiresIn: number;\n}\n\n/**\n * Result from authentication operations (sign-in, verify OTP, etc.)\n */\nexport interface AuthResult {\n user: AuthUser;\n customToken: string;\n isNewUser: boolean;\n}\n\n/**\n * Current authentication state\n */\nexport interface AuthState {\n /** Whether the user is authenticated */\n isAuthenticated: boolean;\n /** Whether auth state is being loaded/verified */\n isLoading: boolean;\n /** Current user if authenticated */\n user: AuthUser | null;\n /** Access token if authenticated */\n accessToken: string | null;\n /** Error if last operation failed */\n error: AuthError | null;\n}\n\n/**\n * Callback type for auth state changes\n */\nexport type AuthStateListener = (state: AuthState) => void;\n\n/**\n * Unsubscribe function returned from onAuthStateChanged\n */\nexport type Unsubscribe = () => void;\n\n/**\n * OTP contact type\n */\nexport type OTPType = 'email' | 'phone';\n\n/**\n * OTP request input\n */\nexport interface OTPRequestInput {\n /** Contact (email or phone) to send OTP to */\n contact: string;\n /** Type of contact */\n type: OTPType;\n /** Optional channel ID */\n channelId?: string;\n}\n\n/**\n * OTP verify input\n */\nexport interface OTPVerifyInput {\n /** Contact (email or phone) that received the OTP */\n contact: string;\n /** OTP code to verify */\n code: string;\n /** Optional channel ID */\n channelId?: string;\n}\n\n/**\n * Input for manually setting authenticated state (for custom auth flows)\n */\nexport interface SetAuthenticatedInput {\n /** Access token */\n accessToken: string;\n /** User object */\n user: AuthUser;\n /** Refresh token (optional) */\n refreshToken?: string;\n /** Token expiry in seconds (default: 7 days) */\n expiresIn?: number;\n}\n\n/**\n * Token refresh input\n */\nexport interface TokenRefreshInput {\n /** Refresh token to exchange for new tokens */\n refreshToken: string;\n /** Optional channel ID */\n channelId?: string;\n}\n\n/**\n * Token validate input\n */\nexport interface TokenValidateInput {\n /** Access token to validate */\n accessToken: string;\n}\n\n/**\n * Token validate response\n */\nexport interface TokenValidateResult {\n valid: boolean;\n uid?: string;\n channelId?: string;\n exp?: number;\n iat?: number;\n}\n\n/**\n * Error codes for auth operations\n */\nexport type AuthErrorCode =\n | 'INVALID_EMAIL'\n | 'INVALID_PHONE'\n | 'INVALID_CONTACT'\n | 'INVALID_OTP'\n | 'OTP_EXPIRED'\n | 'INVALID_TOKEN'\n | 'TOKEN_EXPIRED'\n | 'NETWORK_ERROR'\n | 'SERVER_ERROR'\n | 'UNAUTHORIZED'\n | 'NOT_AUTHENTICATED'\n | 'STORAGE_ERROR'\n | 'UNKNOWN_ERROR';\n\n/**\n * Auth error with typed error codes\n */\nexport class AuthError extends Error {\n code: AuthErrorCode;\n statusCode?: number;\n originalError?: Error;\n\n constructor(message: string, code: AuthErrorCode, statusCode?: number, originalError?: Error) {\n super(message);\n this.name = 'AuthError';\n this.code = code;\n this.statusCode = statusCode;\n this.originalError = originalError;\n }\n\n static fromError(error: Error, code: AuthErrorCode = 'UNKNOWN_ERROR'): AuthError {\n if (error instanceof AuthError) {\n return error;\n }\n return new AuthError(error.message, code, undefined, error);\n }\n}\n","import { AuthError, AuthErrorCode } from './types';\n\n/**\n * Factory functions for creating typed auth errors\n */\nexport const authErrors = {\n invalidEmail: () => new AuthError('Invalid email address', 'INVALID_EMAIL', 400),\n\n invalidOTP: () => new AuthError('Invalid or incorrect OTP code', 'INVALID_OTP', 400),\n\n otpExpired: () => new AuthError('OTP code has expired', 'OTP_EXPIRED', 400),\n\n invalidToken: () => new AuthError('Invalid token', 'INVALID_TOKEN', 401),\n\n tokenExpired: () => new AuthError('Token has expired', 'TOKEN_EXPIRED', 401),\n\n networkError: (message = 'Network request failed') =>\n new AuthError(message, 'NETWORK_ERROR'),\n\n serverError: (message = 'Server error', statusCode = 500) =>\n new AuthError(message, 'SERVER_ERROR', statusCode),\n\n unauthorized: () => new AuthError('Unauthorized', 'UNAUTHORIZED', 401),\n\n notAuthenticated: () => new AuthError('User is not authenticated', 'NOT_AUTHENTICATED'),\n\n storageError: (message = 'Storage operation failed') =>\n new AuthError(message, 'STORAGE_ERROR'),\n\n unknown: (message = 'An unknown error occurred') =>\n new AuthError(message, 'UNKNOWN_ERROR'),\n};\n\n/**\n * Parse error response from API\n */\nexport function parseApiError(response: Response, body: unknown): AuthError {\n const statusCode = response.status;\n\n // Try to extract error message from response body\n let message = response.statusText || 'Request failed';\n if (typeof body === 'object' && body !== null) {\n const errorBody = body as { error?: string; message?: string };\n message = errorBody.error || errorBody.message || message;\n } else if (typeof body === 'string') {\n message = body;\n }\n\n // Map status codes to error codes\n let code: AuthErrorCode;\n switch (statusCode) {\n case 400:\n // Could be invalid email, invalid OTP, etc. - use generic for now\n code = 'INVALID_TOKEN';\n break;\n case 401:\n code = 'UNAUTHORIZED';\n break;\n case 403:\n code = 'UNAUTHORIZED';\n break;\n case 404:\n code = 'SERVER_ERROR';\n break;\n default:\n code = statusCode >= 500 ? 'SERVER_ERROR' : 'UNKNOWN_ERROR';\n }\n\n return new AuthError(message, code, statusCode);\n}\n","import { AuthError } from './types';\n\nconst TOKEN_KEYS = {\n ACCESS_TOKEN: 'cohost_auth_access_token',\n REFRESH_TOKEN: 'cohost_auth_refresh_token',\n TOKEN_EXPIRY: 'cohost_auth_token_expiry',\n USER: 'cohost_auth_user',\n} as const;\n\n/**\n * Storage abstraction interface for token persistence\n */\nexport interface TokenStorage {\n getAccessToken(): string | null;\n setAccessToken(token: string): void;\n getRefreshToken(): string | null;\n setRefreshToken(token: string): void;\n getTokenExpiry(): number | null;\n setTokenExpiry(expiry: number): void;\n getUser<T>(): T | null;\n setUser<T>(user: T): void;\n clear(): void;\n}\n\n/**\n * Check if we're in a browser environment\n */\nfunction isBrowser(): boolean {\n return typeof window !== 'undefined' && typeof window.localStorage !== 'undefined';\n}\n\n/**\n * Web storage implementation (localStorage/sessionStorage)\n */\nclass WebStorage implements TokenStorage {\n private storage: Storage;\n\n constructor(type: 'localStorage' | 'sessionStorage') {\n if (!isBrowser()) {\n throw new AuthError(\n 'Web storage is not available in this environment',\n 'STORAGE_ERROR'\n );\n }\n this.storage = type === 'localStorage' ? window.localStorage : window.sessionStorage;\n }\n\n getAccessToken(): string | null {\n try {\n return this.storage.getItem(TOKEN_KEYS.ACCESS_TOKEN);\n } catch {\n return null;\n }\n }\n\n setAccessToken(token: string): void {\n try {\n this.storage.setItem(TOKEN_KEYS.ACCESS_TOKEN, token);\n } catch (error) {\n throw new AuthError('Failed to save access token', 'STORAGE_ERROR');\n }\n }\n\n getRefreshToken(): string | null {\n try {\n return this.storage.getItem(TOKEN_KEYS.REFRESH_TOKEN);\n } catch {\n return null;\n }\n }\n\n setRefreshToken(token: string): void {\n try {\n this.storage.setItem(TOKEN_KEYS.REFRESH_TOKEN, token);\n } catch (error) {\n throw new AuthError('Failed to save refresh token', 'STORAGE_ERROR');\n }\n }\n\n getTokenExpiry(): number | null {\n try {\n const expiry = this.storage.getItem(TOKEN_KEYS.TOKEN_EXPIRY);\n return expiry ? parseInt(expiry, 10) : null;\n } catch {\n return null;\n }\n }\n\n setTokenExpiry(expiry: number): void {\n try {\n this.storage.setItem(TOKEN_KEYS.TOKEN_EXPIRY, expiry.toString());\n } catch (error) {\n throw new AuthError('Failed to save token expiry', 'STORAGE_ERROR');\n }\n }\n\n getUser<T>(): T | null {\n try {\n const user = this.storage.getItem(TOKEN_KEYS.USER);\n return user ? JSON.parse(user) : null;\n } catch {\n return null;\n }\n }\n\n setUser<T>(user: T): void {\n try {\n this.storage.setItem(TOKEN_KEYS.USER, JSON.stringify(user));\n } catch (error) {\n throw new AuthError('Failed to save user', 'STORAGE_ERROR');\n }\n }\n\n clear(): void {\n try {\n this.storage.removeItem(TOKEN_KEYS.ACCESS_TOKEN);\n this.storage.removeItem(TOKEN_KEYS.REFRESH_TOKEN);\n this.storage.removeItem(TOKEN_KEYS.TOKEN_EXPIRY);\n this.storage.removeItem(TOKEN_KEYS.USER);\n } catch {\n // Silently fail on clear errors\n }\n }\n}\n\n/**\n * In-memory storage implementation (for SSR or non-browser environments)\n */\nclass MemoryStorage implements TokenStorage {\n private accessToken: string | null = null;\n private refreshToken: string | null = null;\n private tokenExpiry: number | null = null;\n private user: unknown = null;\n\n getAccessToken(): string | null {\n return this.accessToken;\n }\n\n setAccessToken(token: string): void {\n this.accessToken = token;\n }\n\n getRefreshToken(): string | null {\n return this.refreshToken;\n }\n\n setRefreshToken(token: string): void {\n this.refreshToken = token;\n }\n\n getTokenExpiry(): number | null {\n return this.tokenExpiry;\n }\n\n setTokenExpiry(expiry: number): void {\n this.tokenExpiry = expiry;\n }\n\n getUser<T>(): T | null {\n return this.user as T | null;\n }\n\n setUser<T>(user: T): void {\n this.user = user;\n }\n\n clear(): void {\n this.accessToken = null;\n this.refreshToken = null;\n this.tokenExpiry = null;\n this.user = null;\n }\n}\n\n/**\n * Create a storage instance based on type\n */\nexport function createStorage(type: 'localStorage' | 'sessionStorage' | 'memory'): TokenStorage {\n if (type === 'memory' || !isBrowser()) {\n return new MemoryStorage();\n }\n return new WebStorage(type);\n}\n\nexport { MemoryStorage, WebStorage };\n","import {\n AuthResult,\n AuthUser,\n TokenPair,\n TokenValidateResult,\n OTPRequestInput,\n OTPVerifyInput,\n TokenRefreshInput,\n TokenValidateInput,\n} from './types';\nimport { parseApiError, authErrors } from './errors';\n\n/**\n * API response wrapper\n */\ninterface ApiResponse<T> {\n status: 'ok' | 'error';\n data: T;\n}\n\n/**\n * Options for API requests\n */\ninterface RequestOptions {\n method?: 'GET' | 'POST' | 'PUT' | 'DELETE';\n body?: unknown;\n headers?: Record<string, string>;\n token?: string;\n}\n\n/**\n * Auth API client for making requests to auth endpoints\n */\nexport class AuthApi {\n private baseUrl: string;\n private debug: boolean;\n\n constructor(baseUrl: string, debug = false) {\n // Remove trailing slash if present\n this.baseUrl = baseUrl.replace(/\\/$/, '');\n this.debug = debug;\n }\n\n /**\n * Make an authenticated or unauthenticated request\n */\n private async request<T>(path: string, options: RequestOptions = {}): Promise<T> {\n const { method = 'GET', body, headers = {}, token } = options;\n\n const url = `${this.baseUrl}${path}`;\n\n const reqHeaders: Record<string, string> = {\n 'Content-Type': 'application/json',\n ...headers,\n };\n\n if (token) {\n reqHeaders['Authorization'] = `Bearer ${token}`;\n }\n\n if (this.debug) {\n console.log(`[AuthClient] ${method} ${url}`);\n if (body) {\n console.log('[AuthClient] Body:', JSON.stringify(body));\n }\n }\n\n let response: Response;\n try {\n response = await fetch(url, {\n method,\n headers: reqHeaders,\n body: body ? JSON.stringify(body) : undefined,\n });\n } catch (error) {\n throw authErrors.networkError(\n error instanceof Error ? error.message : 'Network request failed'\n );\n }\n\n const isJson = response.headers.get('content-type')?.includes('application/json');\n const responseBody = isJson ? await response.json() : await response.text();\n\n if (this.debug) {\n console.log(`[AuthClient] Response (${response.status}):`, responseBody);\n }\n\n if (!response.ok) {\n throw parseApiError(response, responseBody);\n }\n\n // Unwrap API response format { status: 'ok', data: ... }\n if (\n typeof responseBody === 'object' &&\n responseBody !== null &&\n (responseBody as ApiResponse<T>).status === 'ok' &&\n 'data' in responseBody\n ) {\n return (responseBody as ApiResponse<T>).data;\n }\n\n return responseBody as T;\n }\n\n // === OTP Methods ===\n\n /**\n * Request OTP code to be sent to contact (email or phone)\n */\n async requestOTP(input: OTPRequestInput): Promise<{ sent: boolean }> {\n return this.request('/otp/request', {\n method: 'POST',\n body: input,\n });\n }\n\n /**\n * Verify OTP code and get auth result\n */\n async verifyOTP(input: OTPVerifyInput): Promise<AuthResult> {\n return this.request('/otp/verify', {\n method: 'POST',\n body: input,\n });\n }\n\n // === Token Methods ===\n\n /**\n * Refresh token pair using refresh token\n */\n async refreshToken(input: TokenRefreshInput): Promise<TokenPair> {\n return this.request('/token/refresh', {\n method: 'POST',\n body: input,\n });\n }\n\n /**\n * Validate access token\n */\n async validateToken(input: TokenValidateInput): Promise<TokenValidateResult> {\n return this.request('/token/validate', {\n method: 'POST',\n body: input,\n });\n }\n\n /**\n * Revoke token (sign out)\n */\n async revokeToken(token: string): Promise<{ revoked: boolean }> {\n return this.request('/token/revoke', {\n method: 'POST',\n token,\n });\n }\n\n // === User Methods ===\n\n /**\n * Get current authenticated user\n */\n async getCurrentUser(token: string): Promise<{ user: AuthUser; channelId?: string }> {\n return this.request('/me', {\n method: 'GET',\n token,\n });\n }\n}\n","import {\n AuthConfig,\n AuthState,\n AuthUser,\n AuthStateListener,\n Unsubscribe,\n AuthError,\n OTPRequestInput,\n OTPVerifyInput,\n OTPType,\n SetAuthenticatedInput,\n} from './types';\nimport { authErrors } from './errors';\nimport { createStorage, TokenStorage } from './storage';\nimport { AuthApi } from './api';\n\nconst DEFAULT_REFRESH_THRESHOLD = 300; // 5 minutes in seconds\n\n/**\n * Main auth client class for managing authentication state\n */\nexport class AuthClient {\n private config: Required<Omit<AuthConfig, 'channelId'>> & { channelId?: string };\n private storage: TokenStorage;\n private api: AuthApi;\n private state: AuthState;\n private listeners: Set<AuthStateListener> = new Set();\n private refreshTimer: ReturnType<typeof setTimeout> | null = null;\n private initialized = false;\n\n constructor(config: AuthConfig) {\n this.config = {\n apiUrl: config.apiUrl,\n channelId: config.channelId,\n storage: config.storage ?? 'localStorage',\n debug: config.debug ?? false,\n autoRefresh: config.autoRefresh ?? true,\n refreshThreshold: config.refreshThreshold ?? DEFAULT_REFRESH_THRESHOLD,\n };\n\n this.storage = createStorage(this.config.storage);\n this.api = new AuthApi(this.config.apiUrl, this.config.debug);\n\n // Initialize state\n this.state = {\n isAuthenticated: false,\n isLoading: true,\n user: null,\n accessToken: null,\n error: null,\n };\n }\n\n /**\n * Initialize the auth client by loading saved state\n */\n async initialize(): Promise<void> {\n if (this.initialized) {\n return;\n }\n\n this.debug('Initializing auth client');\n\n try {\n const accessToken = this.storage.getAccessToken();\n const user = this.storage.getUser<AuthUser>();\n const expiry = this.storage.getTokenExpiry();\n\n if (accessToken && user && expiry) {\n // Check if token is expired\n const now = Math.floor(Date.now() / 1000);\n if (expiry > now) {\n // Token is valid, restore state\n this.updateState({\n isAuthenticated: true,\n isLoading: false,\n user,\n accessToken,\n error: null,\n });\n\n // Set up auto-refresh if enabled\n if (this.config.autoRefresh) {\n this.scheduleRefresh(expiry - now);\n }\n\n this.initialized = true;\n return;\n }\n\n // Token expired, try to refresh\n const refreshToken = this.storage.getRefreshToken();\n if (refreshToken) {\n await this.performRefresh(refreshToken);\n this.initialized = true;\n return;\n }\n }\n\n // No valid session, clear and set as not authenticated\n this.storage.clear();\n this.updateState({\n isAuthenticated: false,\n isLoading: false,\n user: null,\n accessToken: null,\n error: null,\n });\n } catch (error) {\n this.debug('Initialization error:', error);\n this.storage.clear();\n this.updateState({\n isAuthenticated: false,\n isLoading: false,\n user: null,\n accessToken: null,\n error: AuthError.fromError(error as Error),\n });\n }\n\n this.initialized = true;\n }\n\n // === Public API ===\n\n /**\n * Get current auth state\n */\n getState(): AuthState {\n return { ...this.state };\n }\n\n /**\n * Subscribe to auth state changes\n */\n onAuthStateChanged(listener: AuthStateListener): Unsubscribe {\n this.listeners.add(listener);\n // Immediately call with current state\n listener(this.getState());\n return () => {\n this.listeners.delete(listener);\n };\n }\n\n /**\n * Check if user is authenticated\n */\n get isAuthenticated(): boolean {\n return this.state.isAuthenticated;\n }\n\n /**\n * Get current user\n */\n get currentUser(): AuthUser | null {\n return this.state.user;\n }\n\n /**\n * Get current access token\n */\n get accessToken(): string | null {\n return this.state.accessToken;\n }\n\n // === OTP Authentication ===\n\n /**\n * Request OTP code to be sent to contact (email or phone)\n * @param contact - Email address or phone number\n * @param type - Type of contact ('email' or 'phone')\n */\n async requestOTP(contact: string, type: OTPType = 'email'): Promise<boolean> {\n this.debug('Requesting OTP for:', contact, type);\n\n const input: OTPRequestInput = {\n contact,\n type,\n channelId: this.config.channelId,\n };\n\n const result = await this.api.requestOTP(input);\n return result.sent;\n }\n\n /**\n * Verify OTP code and sign in\n * @param contact - Email address or phone number that received the OTP\n * @param code - OTP code to verify\n */\n async verifyOTP(contact: string, code: string): Promise<AuthUser> {\n this.debug('Verifying OTP for:', contact);\n\n const input: OTPVerifyInput = {\n contact,\n code,\n channelId: this.config.channelId,\n };\n\n const result = await this.api.verifyOTP(input);\n\n // The customToken from verifyOTP is a JWT that we use as our access token\n // We need to also get a refresh token by calling refresh endpoint\n // For now, we'll store the customToken as access token\n // TODO: Backend should return both access and refresh tokens\n\n // Store tokens and user\n this.storage.setAccessToken(result.customToken);\n this.storage.setUser(result.user);\n\n // Set expiry (assume 7 days if not provided)\n const expiry = Math.floor(Date.now() / 1000) + 7 * 24 * 60 * 60;\n this.storage.setTokenExpiry(expiry);\n\n this.updateState({\n isAuthenticated: true,\n isLoading: false,\n user: result.user,\n accessToken: result.customToken,\n error: null,\n });\n\n if (this.config.autoRefresh) {\n this.scheduleRefresh(7 * 24 * 60 * 60);\n }\n\n return result.user;\n }\n\n // === Custom Auth Flow ===\n\n /**\n * Manually set authenticated state after a custom auth flow (e.g., passkey)\n * Use this when you handle authentication outside the standard OTP flow\n */\n setAuthenticated(input: SetAuthenticatedInput): void {\n this.debug('Setting authenticated state for:', input.user.uid);\n\n const { accessToken, user, refreshToken, expiresIn = 7 * 24 * 60 * 60 } = input;\n\n // Store tokens and user\n this.storage.setAccessToken(accessToken);\n this.storage.setUser(user);\n\n if (refreshToken) {\n this.storage.setRefreshToken(refreshToken);\n }\n\n const expiry = Math.floor(Date.now() / 1000) + expiresIn;\n this.storage.setTokenExpiry(expiry);\n\n this.updateState({\n isAuthenticated: true,\n isLoading: false,\n user,\n accessToken,\n error: null,\n });\n\n if (this.config.autoRefresh && refreshToken) {\n this.scheduleRefresh(expiresIn);\n }\n }\n\n // === Token Management ===\n\n /**\n * Get current access token, refreshing if needed\n */\n async getToken(): Promise<string | null> {\n if (!this.state.accessToken) {\n return null;\n }\n\n // Check if token needs refresh\n const expiry = this.storage.getTokenExpiry();\n const now = Math.floor(Date.now() / 1000);\n\n if (expiry && expiry - now < this.config.refreshThreshold) {\n const refreshToken = this.storage.getRefreshToken();\n if (refreshToken) {\n await this.performRefresh(refreshToken);\n }\n }\n\n return this.state.accessToken;\n }\n\n /**\n * Manually refresh the token\n */\n async refreshToken(): Promise<void> {\n const refreshToken = this.storage.getRefreshToken();\n if (!refreshToken) {\n throw authErrors.notAuthenticated();\n }\n await this.performRefresh(refreshToken);\n }\n\n /**\n * Sign out and clear all tokens\n */\n async signOut(): Promise<void> {\n this.debug('Signing out');\n\n // Cancel any pending refresh\n if (this.refreshTimer) {\n clearTimeout(this.refreshTimer);\n this.refreshTimer = null;\n }\n\n // Try to revoke token on server (best effort)\n if (this.state.accessToken) {\n try {\n await this.api.revokeToken(this.state.accessToken);\n } catch (error) {\n this.debug('Revoke token error (ignored):', error);\n }\n }\n\n // Clear storage\n this.storage.clear();\n\n // Update state\n this.updateState({\n isAuthenticated: false,\n isLoading: false,\n user: null,\n accessToken: null,\n error: null,\n });\n }\n\n // === User ===\n\n /**\n * Get current user from server\n */\n async getCurrentUser(): Promise<AuthUser | null> {\n if (!this.state.accessToken) {\n return null;\n }\n\n const result = await this.api.getCurrentUser(this.state.accessToken);\n\n // Update stored user\n this.storage.setUser(result.user);\n this.updateState({\n ...this.state,\n user: result.user,\n });\n\n return result.user;\n }\n\n // === Private Methods ===\n\n private updateState(newState: AuthState): void {\n this.state = newState;\n // Notify all listeners\n for (const listener of this.listeners) {\n try {\n listener(this.getState());\n } catch (error) {\n this.debug('Listener error:', error);\n }\n }\n }\n\n private async performRefresh(refreshToken: string): Promise<void> {\n this.debug('Refreshing token');\n\n try {\n const result = await this.api.refreshToken({\n refreshToken,\n channelId: this.config.channelId,\n });\n\n // Store new tokens\n this.storage.setAccessToken(result.accessToken);\n this.storage.setRefreshToken(result.refreshToken);\n\n const expiry = Math.floor(Date.now() / 1000) + result.expiresIn;\n this.storage.setTokenExpiry(expiry);\n\n // Update state with new token\n this.updateState({\n ...this.state,\n accessToken: result.accessToken,\n error: null,\n });\n\n // Schedule next refresh\n if (this.config.autoRefresh) {\n this.scheduleRefresh(result.expiresIn);\n }\n } catch (error) {\n this.debug('Refresh failed:', error);\n // On refresh failure, sign out\n this.storage.clear();\n this.updateState({\n isAuthenticated: false,\n isLoading: false,\n user: null,\n accessToken: null,\n error: AuthError.fromError(error as Error, 'TOKEN_EXPIRED'),\n });\n }\n }\n\n private scheduleRefresh(expiresIn: number): void {\n if (this.refreshTimer) {\n clearTimeout(this.refreshTimer);\n }\n\n // Refresh when threshold is reached\n const refreshIn = Math.max(0, expiresIn - this.config.refreshThreshold) * 1000;\n\n this.debug(`Scheduling refresh in ${refreshIn / 1000}s`);\n\n this.refreshTimer = setTimeout(() => {\n const refreshToken = this.storage.getRefreshToken();\n if (refreshToken) {\n this.performRefresh(refreshToken);\n }\n }, refreshIn);\n }\n\n private debug(...args: unknown[]): void {\n if (this.config.debug) {\n console.log('[AuthClient]', ...args);\n }\n }\n}\n","// Main exports\nexport { AuthClient } from './client';\nexport { AuthApi } from './api';\n\n// Storage\nexport { createStorage, type TokenStorage } from './storage';\n\n// Types\nexport {\n type AuthConfig,\n type AuthState,\n type AuthUser,\n type AuthResult,\n type TokenPair,\n type AuthStateListener,\n type Unsubscribe,\n type OTPType,\n type OTPRequestInput,\n type OTPVerifyInput,\n type SetAuthenticatedInput,\n type TokenRefreshInput,\n type TokenValidateInput,\n type TokenValidateResult,\n type AuthErrorCode,\n AuthError,\n} from './types';\n\n// Errors\nexport { authErrors } from './errors';\n\nimport { AuthClient } from './client';\nimport { AuthConfig } from './types';\n\n/**\n * Factory function for creating an AuthClient instance\n *\n * @example\n * ```ts\n * import { createAuthClient } from '@cohostvip/cohost-auth';\n *\n * // apiUrl should include the auth path prefix\n * const auth = createAuthClient({\n * apiUrl: 'https://api.cohost.vip/v1/auth', // or '/auth' for relative paths\n * channelId: 'my-channel',\n * });\n *\n * await auth.initialize();\n *\n * // Request OTP (email or phone)\n * await auth.requestOTP('user@example.com', 'email');\n * await auth.requestOTP('+1234567890', 'phone');\n *\n * // Verify OTP\n * const user = await auth.verifyOTP('user@example.com', '123456');\n *\n * // For custom auth flows (e.g., passkey), use setAuthenticated\n * auth.setAuthenticated({\n * accessToken: 'token-from-custom-flow',\n * user: { uid: '123', email: 'user@example.com', ... },\n * });\n *\n * // Check auth state\n * if (auth.isAuthenticated) {\n * console.log('Logged in as:', auth.currentUser?.email);\n * }\n *\n * // Listen for auth changes\n * auth.onAuthStateChanged((state) => {\n * console.log('Auth state changed:', state);\n * });\n *\n * // Sign out\n * await auth.signOut();\n * ```\n */\nexport function createAuthClient(config: AuthConfig): AuthClient {\n return new AuthClient(config);\n}\n"],"mappings":"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","names":["AuthError","_AuthError","message","code","statusCode","originalError","__publicField","error","authErrors","AuthError","message","statusCode","parseApiError","response","body","errorBody","code","TOKEN_KEYS","isBrowser","WebStorage","type","__publicField","AuthError","token","expiry","user","MemoryStorage","createStorage","AuthApi","baseUrl","debug","__publicField","path","options","method","body","headers","token","url","reqHeaders","response","error","authErrors","responseBody","parseApiError","input","DEFAULT_REFRESH_THRESHOLD","AuthClient","config","__publicField","createStorage","AuthApi","accessToken","user","expiry","now","refreshToken","error","AuthError","listener","contact","type","input","code","result","expiresIn","authErrors","newState","refreshIn","args","createAuthClient","config","AuthClient"]}
|
|
1
|
+
{"version":3,"sources":["../src/types.ts","../src/errors.ts","../src/storage.ts","../src/api.ts","../src/client.ts","../src/index.ts"],"sourcesContent":["/**\n * Configuration options for initializing AuthClient\n */\nexport interface AuthConfig {\n /** Base URL for the auth API (e.g., 'https://api.cohost.vip' or '/api') */\n apiUrl: string;\n /** Optional channel ID for multi-tenant scenarios */\n channelId?: string;\n /** Storage type for tokens (default: 'localStorage') */\n storage?: 'localStorage' | 'sessionStorage' | 'memory';\n /** Enable debug logging */\n debug?: boolean;\n /** Auto-refresh tokens before expiry (default: true) */\n autoRefresh?: boolean;\n /** Refresh tokens this many seconds before expiry (default: 300 = 5 minutes) */\n refreshThreshold?: number;\n /**\n * Query string parameter name for token-based authentication (e.g., 'token' or 't').\n * If set, the client will check for this param and attempt to authenticate with it.\n * If not set, token param detection is disabled.\n */\n tokenParam?: string;\n}\n\n/**\n * User object returned from auth endpoints\n */\nexport interface AuthUser {\n uid: string;\n email: string;\n emailVerified: boolean;\n displayName?: string;\n photoURL?: string;\n phoneNumber?: string;\n provider: string;\n providerId: string;\n}\n\n/**\n * Token pair returned from authentication\n */\nexport interface TokenPair {\n accessToken: string;\n refreshToken: string;\n expiresIn: number;\n}\n\n/**\n * Result from authentication operations (sign-in, verify OTP, etc.)\n */\nexport interface AuthResult {\n user: AuthUser;\n customToken: string;\n isNewUser: boolean;\n}\n\n/**\n * Current authentication state\n */\nexport interface AuthState {\n /** Whether the user is authenticated */\n isAuthenticated: boolean;\n /** Whether auth state is being loaded/verified */\n isLoading: boolean;\n /** Current user if authenticated */\n user: AuthUser | null;\n /** Access token if authenticated */\n accessToken: string | null;\n /** Error if last operation failed */\n error: AuthError | null;\n}\n\n/**\n * Callback type for auth state changes\n */\nexport type AuthStateListener = (state: AuthState) => void;\n\n/**\n * Unsubscribe function returned from onAuthStateChanged\n */\nexport type Unsubscribe = () => void;\n\n/**\n * OTP contact type\n */\nexport type OTPType = 'email' | 'phone';\n\n/**\n * OTP request input\n */\nexport interface OTPRequestInput {\n /** Contact (email or phone) to send OTP to */\n contact: string;\n /** Type of contact */\n type: OTPType;\n /** Optional channel ID */\n channelId?: string;\n}\n\n/**\n * OTP verify input\n */\nexport interface OTPVerifyInput {\n /** Contact (email or phone) that received the OTP */\n contact: string;\n /** OTP code to verify */\n code: string;\n /** Optional channel ID */\n channelId?: string;\n}\n\n/**\n * Input for manually setting authenticated state (for custom auth flows)\n */\nexport interface SetAuthenticatedInput {\n /** Access token */\n accessToken: string;\n /** User object */\n user: AuthUser;\n /** Refresh token (optional) */\n refreshToken?: string;\n /** Token expiry in seconds (default: 7 days) */\n expiresIn?: number;\n}\n\n/**\n * Token refresh input\n */\nexport interface TokenRefreshInput {\n /** Refresh token to exchange for new tokens */\n refreshToken: string;\n /** Optional channel ID */\n channelId?: string;\n}\n\n/**\n * Token validate input\n */\nexport interface TokenValidateInput {\n /** Access token to validate */\n accessToken: string;\n}\n\n/**\n * Token validate response\n */\nexport interface TokenValidateResult {\n valid: boolean;\n uid?: string;\n channelId?: string;\n exp?: number;\n iat?: number;\n}\n\n/**\n * Result from authenticating with a token\n */\nexport interface TokenAuthResult {\n /** Whether authentication succeeded */\n success: boolean;\n /** User if authentication succeeded */\n user?: AuthUser;\n /** Error message if authentication failed */\n error?: string;\n}\n\n/**\n * Error codes for auth operations\n */\nexport type AuthErrorCode =\n | 'INVALID_EMAIL'\n | 'INVALID_PHONE'\n | 'INVALID_CONTACT'\n | 'INVALID_OTP'\n | 'OTP_EXPIRED'\n | 'INVALID_TOKEN'\n | 'TOKEN_EXPIRED'\n | 'NETWORK_ERROR'\n | 'SERVER_ERROR'\n | 'UNAUTHORIZED'\n | 'NOT_AUTHENTICATED'\n | 'STORAGE_ERROR'\n | 'UNKNOWN_ERROR';\n\n/**\n * Auth error with typed error codes\n */\nexport class AuthError extends Error {\n code: AuthErrorCode;\n statusCode?: number;\n originalError?: Error;\n\n constructor(message: string, code: AuthErrorCode, statusCode?: number, originalError?: Error) {\n super(message);\n this.name = 'AuthError';\n this.code = code;\n this.statusCode = statusCode;\n this.originalError = originalError;\n }\n\n static fromError(error: Error, code: AuthErrorCode = 'UNKNOWN_ERROR'): AuthError {\n if (error instanceof AuthError) {\n return error;\n }\n return new AuthError(error.message, code, undefined, error);\n }\n}\n","import { AuthError, AuthErrorCode } from './types';\n\n/**\n * Factory functions for creating typed auth errors\n */\nexport const authErrors = {\n invalidEmail: () => new AuthError('Invalid email address', 'INVALID_EMAIL', 400),\n\n invalidOTP: () => new AuthError('Invalid or incorrect OTP code', 'INVALID_OTP', 400),\n\n otpExpired: () => new AuthError('OTP code has expired', 'OTP_EXPIRED', 400),\n\n invalidToken: () => new AuthError('Invalid token', 'INVALID_TOKEN', 401),\n\n tokenExpired: () => new AuthError('Token has expired', 'TOKEN_EXPIRED', 401),\n\n networkError: (message = 'Network request failed') =>\n new AuthError(message, 'NETWORK_ERROR'),\n\n serverError: (message = 'Server error', statusCode = 500) =>\n new AuthError(message, 'SERVER_ERROR', statusCode),\n\n unauthorized: () => new AuthError('Unauthorized', 'UNAUTHORIZED', 401),\n\n notAuthenticated: () => new AuthError('User is not authenticated', 'NOT_AUTHENTICATED'),\n\n storageError: (message = 'Storage operation failed') =>\n new AuthError(message, 'STORAGE_ERROR'),\n\n unknown: (message = 'An unknown error occurred') =>\n new AuthError(message, 'UNKNOWN_ERROR'),\n};\n\n/**\n * Parse error response from API\n */\nexport function parseApiError(response: Response, body: unknown): AuthError {\n const statusCode = response.status;\n\n // Try to extract error message from response body\n let message = response.statusText || 'Request failed';\n if (typeof body === 'object' && body !== null) {\n const errorBody = body as { error?: string; message?: string };\n message = errorBody.error || errorBody.message || message;\n } else if (typeof body === 'string') {\n message = body;\n }\n\n // Map status codes to error codes\n let code: AuthErrorCode;\n switch (statusCode) {\n case 400:\n // Could be invalid email, invalid OTP, etc. - use generic for now\n code = 'INVALID_TOKEN';\n break;\n case 401:\n code = 'UNAUTHORIZED';\n break;\n case 403:\n code = 'UNAUTHORIZED';\n break;\n case 404:\n code = 'SERVER_ERROR';\n break;\n default:\n code = statusCode >= 500 ? 'SERVER_ERROR' : 'UNKNOWN_ERROR';\n }\n\n return new AuthError(message, code, statusCode);\n}\n","import { AuthError } from './types';\n\nconst TOKEN_KEYS = {\n ACCESS_TOKEN: 'cohost_auth_access_token',\n REFRESH_TOKEN: 'cohost_auth_refresh_token',\n TOKEN_EXPIRY: 'cohost_auth_token_expiry',\n USER: 'cohost_auth_user',\n} as const;\n\n/**\n * Storage abstraction interface for token persistence\n */\nexport interface TokenStorage {\n getAccessToken(): string | null;\n setAccessToken(token: string): void;\n getRefreshToken(): string | null;\n setRefreshToken(token: string): void;\n getTokenExpiry(): number | null;\n setTokenExpiry(expiry: number): void;\n getUser<T>(): T | null;\n setUser<T>(user: T): void;\n clear(): void;\n}\n\n/**\n * Check if we're in a browser environment\n */\nfunction isBrowser(): boolean {\n return typeof window !== 'undefined' && typeof window.localStorage !== 'undefined';\n}\n\n/**\n * Web storage implementation (localStorage/sessionStorage)\n */\nclass WebStorage implements TokenStorage {\n private storage: Storage;\n\n constructor(type: 'localStorage' | 'sessionStorage') {\n if (!isBrowser()) {\n throw new AuthError(\n 'Web storage is not available in this environment',\n 'STORAGE_ERROR'\n );\n }\n this.storage = type === 'localStorage' ? window.localStorage : window.sessionStorage;\n }\n\n getAccessToken(): string | null {\n try {\n return this.storage.getItem(TOKEN_KEYS.ACCESS_TOKEN);\n } catch {\n return null;\n }\n }\n\n setAccessToken(token: string): void {\n try {\n this.storage.setItem(TOKEN_KEYS.ACCESS_TOKEN, token);\n } catch (error) {\n throw new AuthError('Failed to save access token', 'STORAGE_ERROR');\n }\n }\n\n getRefreshToken(): string | null {\n try {\n return this.storage.getItem(TOKEN_KEYS.REFRESH_TOKEN);\n } catch {\n return null;\n }\n }\n\n setRefreshToken(token: string): void {\n try {\n this.storage.setItem(TOKEN_KEYS.REFRESH_TOKEN, token);\n } catch (error) {\n throw new AuthError('Failed to save refresh token', 'STORAGE_ERROR');\n }\n }\n\n getTokenExpiry(): number | null {\n try {\n const expiry = this.storage.getItem(TOKEN_KEYS.TOKEN_EXPIRY);\n return expiry ? parseInt(expiry, 10) : null;\n } catch {\n return null;\n }\n }\n\n setTokenExpiry(expiry: number): void {\n try {\n this.storage.setItem(TOKEN_KEYS.TOKEN_EXPIRY, expiry.toString());\n } catch (error) {\n throw new AuthError('Failed to save token expiry', 'STORAGE_ERROR');\n }\n }\n\n getUser<T>(): T | null {\n try {\n const user = this.storage.getItem(TOKEN_KEYS.USER);\n return user ? JSON.parse(user) : null;\n } catch {\n return null;\n }\n }\n\n setUser<T>(user: T): void {\n try {\n this.storage.setItem(TOKEN_KEYS.USER, JSON.stringify(user));\n } catch (error) {\n throw new AuthError('Failed to save user', 'STORAGE_ERROR');\n }\n }\n\n clear(): void {\n try {\n this.storage.removeItem(TOKEN_KEYS.ACCESS_TOKEN);\n this.storage.removeItem(TOKEN_KEYS.REFRESH_TOKEN);\n this.storage.removeItem(TOKEN_KEYS.TOKEN_EXPIRY);\n this.storage.removeItem(TOKEN_KEYS.USER);\n } catch {\n // Silently fail on clear errors\n }\n }\n}\n\n/**\n * In-memory storage implementation (for SSR or non-browser environments)\n */\nclass MemoryStorage implements TokenStorage {\n private accessToken: string | null = null;\n private refreshToken: string | null = null;\n private tokenExpiry: number | null = null;\n private user: unknown = null;\n\n getAccessToken(): string | null {\n return this.accessToken;\n }\n\n setAccessToken(token: string): void {\n this.accessToken = token;\n }\n\n getRefreshToken(): string | null {\n return this.refreshToken;\n }\n\n setRefreshToken(token: string): void {\n this.refreshToken = token;\n }\n\n getTokenExpiry(): number | null {\n return this.tokenExpiry;\n }\n\n setTokenExpiry(expiry: number): void {\n this.tokenExpiry = expiry;\n }\n\n getUser<T>(): T | null {\n return this.user as T | null;\n }\n\n setUser<T>(user: T): void {\n this.user = user;\n }\n\n clear(): void {\n this.accessToken = null;\n this.refreshToken = null;\n this.tokenExpiry = null;\n this.user = null;\n }\n}\n\n/**\n * Create a storage instance based on type\n */\nexport function createStorage(type: 'localStorage' | 'sessionStorage' | 'memory'): TokenStorage {\n if (type === 'memory' || !isBrowser()) {\n return new MemoryStorage();\n }\n return new WebStorage(type);\n}\n\nexport { MemoryStorage, WebStorage };\n","import {\n AuthResult,\n AuthUser,\n TokenPair,\n TokenValidateResult,\n OTPRequestInput,\n OTPVerifyInput,\n TokenRefreshInput,\n TokenValidateInput,\n} from './types';\nimport { parseApiError, authErrors } from './errors';\n\n/**\n * API response wrapper\n */\ninterface ApiResponse<T> {\n status: 'ok' | 'error';\n data: T;\n}\n\n/**\n * Options for API requests\n */\ninterface RequestOptions {\n method?: 'GET' | 'POST' | 'PUT' | 'DELETE';\n body?: unknown;\n headers?: Record<string, string>;\n token?: string;\n}\n\n/**\n * Auth API client for making requests to auth endpoints\n */\nexport class AuthApi {\n private baseUrl: string;\n private debug: boolean;\n\n constructor(baseUrl: string, debug = false) {\n // Remove trailing slash if present\n this.baseUrl = baseUrl.replace(/\\/$/, '');\n this.debug = debug;\n }\n\n /**\n * Make an authenticated or unauthenticated request\n */\n private async request<T>(path: string, options: RequestOptions = {}): Promise<T> {\n const { method = 'GET', body, headers = {}, token } = options;\n\n const url = `${this.baseUrl}${path}`;\n\n const reqHeaders: Record<string, string> = {\n 'Content-Type': 'application/json',\n ...headers,\n };\n\n if (token) {\n reqHeaders['Authorization'] = `Bearer ${token}`;\n }\n\n if (this.debug) {\n console.log(`[AuthClient] ${method} ${url}`);\n if (body) {\n console.log('[AuthClient] Body:', JSON.stringify(body));\n }\n }\n\n let response: Response;\n try {\n response = await fetch(url, {\n method,\n headers: reqHeaders,\n body: body ? JSON.stringify(body) : undefined,\n });\n } catch (error) {\n throw authErrors.networkError(\n error instanceof Error ? error.message : 'Network request failed'\n );\n }\n\n const isJson = response.headers.get('content-type')?.includes('application/json');\n const responseBody = isJson ? await response.json() : await response.text();\n\n if (this.debug) {\n console.log(`[AuthClient] Response (${response.status}):`, responseBody);\n }\n\n if (!response.ok) {\n throw parseApiError(response, responseBody);\n }\n\n // Unwrap API response format { status: 'ok', data: ... }\n if (\n typeof responseBody === 'object' &&\n responseBody !== null &&\n (responseBody as ApiResponse<T>).status === 'ok' &&\n 'data' in responseBody\n ) {\n return (responseBody as ApiResponse<T>).data;\n }\n\n return responseBody as T;\n }\n\n // === OTP Methods ===\n\n /**\n * Request OTP code to be sent to contact (email or phone)\n */\n async requestOTP(input: OTPRequestInput): Promise<{ sent: boolean }> {\n return this.request('/otp/request', {\n method: 'POST',\n body: input,\n });\n }\n\n /**\n * Verify OTP code and get auth result\n */\n async verifyOTP(input: OTPVerifyInput): Promise<AuthResult> {\n return this.request('/otp/verify', {\n method: 'POST',\n body: input,\n });\n }\n\n // === Token Methods ===\n\n /**\n * Refresh token pair using refresh token\n */\n async refreshToken(input: TokenRefreshInput): Promise<TokenPair> {\n return this.request('/token/refresh', {\n method: 'POST',\n body: input,\n });\n }\n\n /**\n * Validate access token\n */\n async validateToken(input: TokenValidateInput): Promise<TokenValidateResult> {\n return this.request('/token/validate', {\n method: 'POST',\n body: input,\n });\n }\n\n /**\n * Revoke token (sign out)\n */\n async revokeToken(token: string): Promise<{ revoked: boolean }> {\n return this.request('/token/revoke', {\n method: 'POST',\n token,\n });\n }\n\n // === User Methods ===\n\n /**\n * Get current authenticated user\n */\n async getCurrentUser(token: string): Promise<{ user: AuthUser; channelId?: string }> {\n return this.request('/me', {\n method: 'GET',\n token,\n });\n }\n}\n","import {\n AuthConfig,\n AuthState,\n AuthUser,\n AuthStateListener,\n Unsubscribe,\n AuthError,\n OTPRequestInput,\n OTPVerifyInput,\n OTPType,\n SetAuthenticatedInput,\n TokenAuthResult,\n} from './types';\nimport { authErrors } from './errors';\nimport { createStorage, TokenStorage } from './storage';\nimport { AuthApi } from './api';\n\nconst DEFAULT_REFRESH_THRESHOLD = 300; // 5 minutes in seconds\n\n/**\n * Main auth client class for managing authentication state\n */\nexport class AuthClient {\n private config: Required<Omit<AuthConfig, 'channelId' | 'tokenParam'>> & { channelId?: string; tokenParam?: string };\n private storage: TokenStorage;\n private api: AuthApi;\n private state: AuthState;\n private listeners: Set<AuthStateListener> = new Set();\n private refreshTimer: ReturnType<typeof setTimeout> | null = null;\n private initialized = false;\n\n constructor(config: AuthConfig) {\n this.config = {\n apiUrl: config.apiUrl,\n channelId: config.channelId,\n tokenParam: config.tokenParam,\n storage: config.storage ?? 'localStorage',\n debug: config.debug ?? false,\n autoRefresh: config.autoRefresh ?? true,\n refreshThreshold: config.refreshThreshold ?? DEFAULT_REFRESH_THRESHOLD,\n };\n\n this.storage = createStorage(this.config.storage);\n this.api = new AuthApi(this.config.apiUrl, this.config.debug);\n\n // Initialize state\n this.state = {\n isAuthenticated: false,\n isLoading: true,\n user: null,\n accessToken: null,\n error: null,\n };\n }\n\n /**\n * Initialize the auth client by loading saved state\n */\n async initialize(): Promise<void> {\n if (this.initialized) {\n return;\n }\n\n this.debug('Initializing auth client');\n\n try {\n const accessToken = this.storage.getAccessToken();\n const user = this.storage.getUser<AuthUser>();\n const expiry = this.storage.getTokenExpiry();\n\n if (accessToken && user && expiry) {\n // Check if token is expired\n const now = Math.floor(Date.now() / 1000);\n if (expiry > now) {\n // Token is valid, restore state\n this.updateState({\n isAuthenticated: true,\n isLoading: false,\n user,\n accessToken,\n error: null,\n });\n\n // Set up auto-refresh if enabled\n if (this.config.autoRefresh) {\n this.scheduleRefresh(expiry - now);\n }\n\n this.initialized = true;\n return;\n }\n\n // Token expired, try to refresh\n const refreshToken = this.storage.getRefreshToken();\n if (refreshToken) {\n await this.performRefresh(refreshToken);\n this.initialized = true;\n return;\n }\n }\n\n // No valid session, clear and set as not authenticated\n this.storage.clear();\n this.updateState({\n isAuthenticated: false,\n isLoading: false,\n user: null,\n accessToken: null,\n error: null,\n });\n } catch (error) {\n this.debug('Initialization error:', error);\n this.storage.clear();\n this.updateState({\n isAuthenticated: false,\n isLoading: false,\n user: null,\n accessToken: null,\n error: AuthError.fromError(error as Error),\n });\n }\n\n this.initialized = true;\n }\n\n // === Public API ===\n\n /**\n * Get current auth state\n */\n getState(): AuthState {\n return { ...this.state };\n }\n\n /**\n * Subscribe to auth state changes\n */\n onAuthStateChanged(listener: AuthStateListener): Unsubscribe {\n this.listeners.add(listener);\n // Immediately call with current state\n listener(this.getState());\n return () => {\n this.listeners.delete(listener);\n };\n }\n\n /**\n * Check if user is authenticated\n */\n get isAuthenticated(): boolean {\n return this.state.isAuthenticated;\n }\n\n /**\n * Get current user\n */\n get currentUser(): AuthUser | null {\n return this.state.user;\n }\n\n /**\n * Get current access token\n */\n get accessToken(): string | null {\n return this.state.accessToken;\n }\n\n // === OTP Authentication ===\n\n /**\n * Request OTP code to be sent to contact (email or phone)\n * @param contact - Email address or phone number\n * @param type - Type of contact ('email' or 'phone')\n */\n async requestOTP(contact: string, type: OTPType = 'email'): Promise<boolean> {\n this.debug('Requesting OTP for:', contact, type);\n\n const input: OTPRequestInput = {\n contact,\n type,\n channelId: this.config.channelId,\n };\n\n const result = await this.api.requestOTP(input);\n return result.sent;\n }\n\n /**\n * Verify OTP code and sign in\n * @param contact - Email address or phone number that received the OTP\n * @param code - OTP code to verify\n */\n async verifyOTP(contact: string, code: string): Promise<AuthUser> {\n this.debug('Verifying OTP for:', contact);\n\n const input: OTPVerifyInput = {\n contact,\n code,\n channelId: this.config.channelId,\n };\n\n const result = await this.api.verifyOTP(input);\n\n // The customToken from verifyOTP is a JWT that we use as our access token\n // We need to also get a refresh token by calling refresh endpoint\n // For now, we'll store the customToken as access token\n // TODO: Backend should return both access and refresh tokens\n\n // Store tokens and user\n this.storage.setAccessToken(result.customToken);\n this.storage.setUser(result.user);\n\n // Set expiry (assume 7 days if not provided)\n const expiry = Math.floor(Date.now() / 1000) + 7 * 24 * 60 * 60;\n this.storage.setTokenExpiry(expiry);\n\n this.updateState({\n isAuthenticated: true,\n isLoading: false,\n user: result.user,\n accessToken: result.customToken,\n error: null,\n });\n\n if (this.config.autoRefresh) {\n this.scheduleRefresh(7 * 24 * 60 * 60);\n }\n\n return result.user;\n }\n\n // === Custom Auth Flow ===\n\n /**\n * Manually set authenticated state after a custom auth flow (e.g., passkey)\n * Use this when you handle authentication outside the standard OTP flow\n */\n setAuthenticated(input: SetAuthenticatedInput): void {\n this.debug('Setting authenticated state for:', input.user.uid);\n\n const { accessToken, user, refreshToken, expiresIn = 7 * 24 * 60 * 60 } = input;\n\n // Store tokens and user\n this.storage.setAccessToken(accessToken);\n this.storage.setUser(user);\n\n if (refreshToken) {\n this.storage.setRefreshToken(refreshToken);\n }\n\n const expiry = Math.floor(Date.now() / 1000) + expiresIn;\n this.storage.setTokenExpiry(expiry);\n\n this.updateState({\n isAuthenticated: true,\n isLoading: false,\n user,\n accessToken,\n error: null,\n });\n\n if (this.config.autoRefresh && refreshToken) {\n this.scheduleRefresh(expiresIn);\n }\n }\n\n /**\n * Get the configured token param name (if any)\n * Returns undefined if token param detection is disabled\n */\n get tokenParamName(): string | undefined {\n return this.config.tokenParam;\n }\n\n /**\n * Authenticate using a token (e.g., from URL query param).\n * Validates the token via API and sets auth state if valid.\n * @param token - The token to authenticate with\n * @returns Result indicating success/failure\n */\n async authenticateWithToken(token: string): Promise<TokenAuthResult> {\n this.debug('Authenticating with token');\n\n // Set loading state while authenticating\n this.updateState({\n ...this.state,\n isLoading: true,\n error: null,\n });\n\n try {\n // Validate the token via API\n const validateResult = await this.api.validateToken({ accessToken: token });\n\n if (!validateResult.valid || !validateResult.uid) {\n this.debug('Token validation failed: invalid token');\n this.updateState({\n ...this.state,\n isLoading: false,\n });\n return { success: false, error: 'Invalid token' };\n }\n\n // Get user info from the token\n const userResult = await this.api.getCurrentUser(token);\n\n // Calculate expiry from token\n const now = Math.floor(Date.now() / 1000);\n const expiresIn = validateResult.exp ? validateResult.exp - now : 7 * 24 * 60 * 60;\n\n // Set authenticated state (this also sets isLoading: false)\n this.setAuthenticated({\n accessToken: token,\n user: userResult.user,\n expiresIn,\n });\n\n this.debug('Token authentication successful for:', userResult.user.uid);\n\n return { success: true, user: userResult.user };\n } catch (error) {\n this.debug('Token authentication failed:', error);\n this.updateState({\n ...this.state,\n isLoading: false,\n error: AuthError.fromError(error as Error, 'INVALID_TOKEN'),\n });\n const message = error instanceof Error ? error.message : 'Token authentication failed';\n return { success: false, error: message };\n }\n }\n\n // === Token Management ===\n\n /**\n * Get current access token, refreshing if needed\n */\n async getToken(): Promise<string | null> {\n if (!this.state.accessToken) {\n return null;\n }\n\n // Check if token needs refresh\n const expiry = this.storage.getTokenExpiry();\n const now = Math.floor(Date.now() / 1000);\n\n if (expiry && expiry - now < this.config.refreshThreshold) {\n const refreshToken = this.storage.getRefreshToken();\n if (refreshToken) {\n await this.performRefresh(refreshToken);\n }\n }\n\n return this.state.accessToken;\n }\n\n /**\n * Manually refresh the token\n */\n async refreshToken(): Promise<void> {\n const refreshToken = this.storage.getRefreshToken();\n if (!refreshToken) {\n throw authErrors.notAuthenticated();\n }\n await this.performRefresh(refreshToken);\n }\n\n /**\n * Sign out and clear all tokens\n */\n async signOut(): Promise<void> {\n this.debug('Signing out');\n\n // Cancel any pending refresh\n if (this.refreshTimer) {\n clearTimeout(this.refreshTimer);\n this.refreshTimer = null;\n }\n\n // Try to revoke token on server (best effort)\n if (this.state.accessToken) {\n try {\n await this.api.revokeToken(this.state.accessToken);\n } catch (error) {\n this.debug('Revoke token error (ignored):', error);\n }\n }\n\n // Clear storage\n this.storage.clear();\n\n // Update state\n this.updateState({\n isAuthenticated: false,\n isLoading: false,\n user: null,\n accessToken: null,\n error: null,\n });\n }\n\n // === User ===\n\n /**\n * Get current user from server\n */\n async getCurrentUser(): Promise<AuthUser | null> {\n if (!this.state.accessToken) {\n return null;\n }\n\n const result = await this.api.getCurrentUser(this.state.accessToken);\n\n // Update stored user\n this.storage.setUser(result.user);\n this.updateState({\n ...this.state,\n user: result.user,\n });\n\n return result.user;\n }\n\n // === Private Methods ===\n\n private updateState(newState: AuthState): void {\n this.state = newState;\n // Notify all listeners\n for (const listener of this.listeners) {\n try {\n listener(this.getState());\n } catch (error) {\n this.debug('Listener error:', error);\n }\n }\n }\n\n private async performRefresh(refreshToken: string): Promise<void> {\n this.debug('Refreshing token');\n\n try {\n const result = await this.api.refreshToken({\n refreshToken,\n channelId: this.config.channelId,\n });\n\n // Store new tokens\n this.storage.setAccessToken(result.accessToken);\n this.storage.setRefreshToken(result.refreshToken);\n\n const expiry = Math.floor(Date.now() / 1000) + result.expiresIn;\n this.storage.setTokenExpiry(expiry);\n\n // Update state with new token\n this.updateState({\n ...this.state,\n accessToken: result.accessToken,\n error: null,\n });\n\n // Schedule next refresh\n if (this.config.autoRefresh) {\n this.scheduleRefresh(result.expiresIn);\n }\n } catch (error) {\n this.debug('Refresh failed:', error);\n // On refresh failure, sign out\n this.storage.clear();\n this.updateState({\n isAuthenticated: false,\n isLoading: false,\n user: null,\n accessToken: null,\n error: AuthError.fromError(error as Error, 'TOKEN_EXPIRED'),\n });\n }\n }\n\n private scheduleRefresh(expiresIn: number): void {\n if (this.refreshTimer) {\n clearTimeout(this.refreshTimer);\n }\n\n // Refresh when threshold is reached\n const refreshIn = Math.max(0, expiresIn - this.config.refreshThreshold) * 1000;\n\n this.debug(`Scheduling refresh in ${refreshIn / 1000}s`);\n\n this.refreshTimer = setTimeout(() => {\n const refreshToken = this.storage.getRefreshToken();\n if (refreshToken) {\n this.performRefresh(refreshToken);\n }\n }, refreshIn);\n }\n\n private debug(...args: unknown[]): void {\n if (this.config.debug) {\n console.log('[AuthClient]', ...args);\n }\n }\n}\n","// Main exports\nexport { AuthClient } from './client';\nexport { AuthApi } from './api';\n\n// Storage\nexport { createStorage, type TokenStorage } from './storage';\n\n// Types\nexport {\n type AuthConfig,\n type AuthState,\n type AuthUser,\n type AuthResult,\n type TokenPair,\n type AuthStateListener,\n type Unsubscribe,\n type OTPType,\n type OTPRequestInput,\n type OTPVerifyInput,\n type SetAuthenticatedInput,\n type TokenRefreshInput,\n type TokenValidateInput,\n type TokenValidateResult,\n type TokenAuthResult,\n type AuthErrorCode,\n AuthError,\n} from './types';\n\n// Errors\nexport { authErrors } from './errors';\n\nimport { AuthClient } from './client';\nimport { AuthConfig } from './types';\n\n/**\n * Factory function for creating an AuthClient instance\n *\n * @example\n * ```ts\n * import { createAuthClient } from '@cohostvip/cohost-auth';\n *\n * // apiUrl should include the auth path prefix\n * const auth = createAuthClient({\n * apiUrl: 'https://api.cohost.vip/v1/auth', // or '/auth' for relative paths\n * channelId: 'my-channel',\n * });\n *\n * await auth.initialize();\n *\n * // Request OTP (email or phone)\n * await auth.requestOTP('user@example.com', 'email');\n * await auth.requestOTP('+1234567890', 'phone');\n *\n * // Verify OTP\n * const user = await auth.verifyOTP('user@example.com', '123456');\n *\n * // For custom auth flows (e.g., passkey), use setAuthenticated\n * auth.setAuthenticated({\n * accessToken: 'token-from-custom-flow',\n * user: { uid: '123', email: 'user@example.com', ... },\n * });\n *\n * // Check auth state\n * if (auth.isAuthenticated) {\n * console.log('Logged in as:', auth.currentUser?.email);\n * }\n *\n * // Listen for auth changes\n * auth.onAuthStateChanged((state) => {\n * console.log('Auth state changed:', state);\n * });\n *\n * // Sign out\n * await auth.signOut();\n * ```\n */\nexport function createAuthClient(config: AuthConfig): AuthClient {\n return new AuthClient(config);\n}\n"],"mappings":"oKA2LO,IAAMA,EAAN,MAAMC,UAAkB,KAAM,CAKnC,YAAYC,EAAiBC,EAAqBC,EAAqBC,EAAuB,CAC5F,MAAMH,CAAO,EALfI,EAAA,aACAA,EAAA,mBACAA,EAAA,sBAIE,KAAK,KAAO,YACZ,KAAK,KAAOH,EACZ,KAAK,WAAaC,EAClB,KAAK,cAAgBC,CACvB,CAEA,OAAO,UAAUE,EAAcJ,EAAsB,gBAA4B,CAC/E,OAAII,aAAiBN,EACZM,EAEF,IAAIN,EAAUM,EAAM,QAASJ,EAAM,OAAWI,CAAK,CAC5D,CACF,ECzMO,IAAMC,EAAa,CACxB,aAAc,IAAM,IAAIC,EAAU,wBAAyB,gBAAiB,GAAG,EAE/E,WAAY,IAAM,IAAIA,EAAU,gCAAiC,cAAe,GAAG,EAEnF,WAAY,IAAM,IAAIA,EAAU,uBAAwB,cAAe,GAAG,EAE1E,aAAc,IAAM,IAAIA,EAAU,gBAAiB,gBAAiB,GAAG,EAEvE,aAAc,IAAM,IAAIA,EAAU,oBAAqB,gBAAiB,GAAG,EAE3E,aAAc,CAACC,EAAU,2BACvB,IAAID,EAAUC,EAAS,eAAe,EAExC,YAAa,CAACA,EAAU,eAAgBC,EAAa,MACnD,IAAIF,EAAUC,EAAS,eAAgBC,CAAU,EAEnD,aAAc,IAAM,IAAIF,EAAU,eAAgB,eAAgB,GAAG,EAErE,iBAAkB,IAAM,IAAIA,EAAU,4BAA6B,mBAAmB,EAEtF,aAAc,CAACC,EAAU,6BACvB,IAAID,EAAUC,EAAS,eAAe,EAExC,QAAS,CAACA,EAAU,8BAClB,IAAID,EAAUC,EAAS,eAAe,CAC1C,EAKO,SAASE,EAAcC,EAAoBC,EAA0B,CAC1E,IAAMH,EAAaE,EAAS,OAGxBH,EAAUG,EAAS,YAAc,iBACrC,GAAI,OAAOC,GAAS,UAAYA,IAAS,KAAM,CAC7C,IAAMC,EAAYD,EAClBJ,EAAUK,EAAU,OAASA,EAAU,SAAWL,CACpD,MAAW,OAAOI,GAAS,WACzBJ,EAAUI,GAIZ,IAAIE,EACJ,OAAQL,EAAY,CAClB,IAAK,KAEHK,EAAO,gBACP,MACF,IAAK,KACHA,EAAO,eACP,MACF,IAAK,KACHA,EAAO,eACP,MACF,IAAK,KACHA,EAAO,eACP,MACF,QACEA,EAAOL,GAAc,IAAM,eAAiB,eAChD,CAEA,OAAO,IAAIF,EAAUC,EAASM,EAAML,CAAU,CAChD,CCnEA,IAAMM,EAAa,CACjB,aAAc,2BACd,cAAe,4BACf,aAAc,2BACd,KAAM,kBACR,EAoBA,SAASC,GAAqB,CAC5B,OAAO,OAAO,OAAW,KAAe,OAAO,OAAO,aAAiB,GACzE,CAKA,IAAMC,EAAN,KAAyC,CAGvC,YAAYC,EAAyC,CAFrDC,EAAA,KAAQ,WAGN,GAAI,CAACH,EAAU,EACb,MAAM,IAAII,EACR,mDACA,eACF,EAEF,KAAK,QAAUF,IAAS,eAAiB,OAAO,aAAe,OAAO,cACxE,CAEA,gBAAgC,CAC9B,GAAI,CACF,OAAO,KAAK,QAAQ,QAAQH,EAAW,YAAY,CACrD,MAAQ,CACN,OAAO,IACT,CACF,CAEA,eAAeM,EAAqB,CAClC,GAAI,CACF,KAAK,QAAQ,QAAQN,EAAW,aAAcM,CAAK,CACrD,MAAgB,CACd,MAAM,IAAID,EAAU,8BAA+B,eAAe,CACpE,CACF,CAEA,iBAAiC,CAC/B,GAAI,CACF,OAAO,KAAK,QAAQ,QAAQL,EAAW,aAAa,CACtD,MAAQ,CACN,OAAO,IACT,CACF,CAEA,gBAAgBM,EAAqB,CACnC,GAAI,CACF,KAAK,QAAQ,QAAQN,EAAW,cAAeM,CAAK,CACtD,MAAgB,CACd,MAAM,IAAID,EAAU,+BAAgC,eAAe,CACrE,CACF,CAEA,gBAAgC,CAC9B,GAAI,CACF,IAAME,EAAS,KAAK,QAAQ,QAAQP,EAAW,YAAY,EAC3D,OAAOO,EAAS,SAASA,EAAQ,EAAE,EAAI,IACzC,MAAQ,CACN,OAAO,IACT,CACF,CAEA,eAAeA,EAAsB,CACnC,GAAI,CACF,KAAK,QAAQ,QAAQP,EAAW,aAAcO,EAAO,SAAS,CAAC,CACjE,MAAgB,CACd,MAAM,IAAIF,EAAU,8BAA+B,eAAe,CACpE,CACF,CAEA,SAAuB,CACrB,GAAI,CACF,IAAMG,EAAO,KAAK,QAAQ,QAAQR,EAAW,IAAI,EACjD,OAAOQ,EAAO,KAAK,MAAMA,CAAI,EAAI,IACnC,MAAQ,CACN,OAAO,IACT,CACF,CAEA,QAAWA,EAAe,CACxB,GAAI,CACF,KAAK,QAAQ,QAAQR,EAAW,KAAM,KAAK,UAAUQ,CAAI,CAAC,CAC5D,MAAgB,CACd,MAAM,IAAIH,EAAU,sBAAuB,eAAe,CAC5D,CACF,CAEA,OAAc,CACZ,GAAI,CACF,KAAK,QAAQ,WAAWL,EAAW,YAAY,EAC/C,KAAK,QAAQ,WAAWA,EAAW,aAAa,EAChD,KAAK,QAAQ,WAAWA,EAAW,YAAY,EAC/C,KAAK,QAAQ,WAAWA,EAAW,IAAI,CACzC,MAAQ,CAER,CACF,CACF,EAKMS,EAAN,KAA4C,CAA5C,cACEL,EAAA,KAAQ,cAA6B,MACrCA,EAAA,KAAQ,eAA8B,MACtCA,EAAA,KAAQ,cAA6B,MACrCA,EAAA,KAAQ,OAAgB,MAExB,gBAAgC,CAC9B,OAAO,KAAK,WACd,CAEA,eAAeE,EAAqB,CAClC,KAAK,YAAcA,CACrB,CAEA,iBAAiC,CAC/B,OAAO,KAAK,YACd,CAEA,gBAAgBA,EAAqB,CACnC,KAAK,aAAeA,CACtB,CAEA,gBAAgC,CAC9B,OAAO,KAAK,WACd,CAEA,eAAeC,EAAsB,CACnC,KAAK,YAAcA,CACrB,CAEA,SAAuB,CACrB,OAAO,KAAK,IACd,CAEA,QAAWC,EAAe,CACxB,KAAK,KAAOA,CACd,CAEA,OAAc,CACZ,KAAK,YAAc,KACnB,KAAK,aAAe,KACpB,KAAK,YAAc,KACnB,KAAK,KAAO,IACd,CACF,EAKO,SAASE,EAAcP,EAAkE,CAC9F,OAAIA,IAAS,UAAY,CAACF,EAAU,EAC3B,IAAIQ,EAEN,IAAIP,EAAWC,CAAI,CAC5B,CCrJO,IAAMQ,EAAN,KAAc,CAInB,YAAYC,EAAiBC,EAAQ,GAAO,CAH5CC,EAAA,KAAQ,WACRA,EAAA,KAAQ,SAIN,KAAK,QAAUF,EAAQ,QAAQ,MAAO,EAAE,EACxC,KAAK,MAAQC,CACf,CAKA,MAAc,QAAWE,EAAcC,EAA0B,CAAC,EAAe,CAC/E,GAAM,CAAE,OAAAC,EAAS,MAAO,KAAAC,EAAM,QAAAC,EAAU,CAAC,EAAG,MAAAC,CAAM,EAAIJ,EAEhDK,EAAM,GAAG,KAAK,OAAO,GAAGN,CAAI,GAE5BO,EAAqC,CACzC,eAAgB,mBAChB,GAAGH,CACL,EAEIC,IACFE,EAAW,cAAmB,UAAUF,CAAK,IAG3C,KAAK,QACP,QAAQ,IAAI,gBAAgBH,CAAM,IAAII,CAAG,EAAE,EACvCH,GACF,QAAQ,IAAI,qBAAsB,KAAK,UAAUA,CAAI,CAAC,GAI1D,IAAIK,EACJ,GAAI,CACFA,EAAW,MAAM,MAAMF,EAAK,CAC1B,OAAAJ,EACA,QAASK,EACT,KAAMJ,EAAO,KAAK,UAAUA,CAAI,EAAI,MACtC,CAAC,CACH,OAASM,EAAO,CACd,MAAMC,EAAW,aACfD,aAAiB,MAAQA,EAAM,QAAU,wBAC3C,CACF,CAGA,IAAME,EADSH,EAAS,QAAQ,IAAI,cAAc,GAAG,SAAS,kBAAkB,EAClD,MAAMA,EAAS,KAAK,EAAI,MAAMA,EAAS,KAAK,EAM1E,GAJI,KAAK,OACP,QAAQ,IAAI,0BAA0BA,EAAS,MAAM,KAAMG,CAAY,EAGrE,CAACH,EAAS,GACZ,MAAMI,EAAcJ,EAAUG,CAAY,EAI5C,OACE,OAAOA,GAAiB,UACxBA,IAAiB,MAChBA,EAAgC,SAAW,MAC5C,SAAUA,EAEFA,EAAgC,KAGnCA,CACT,CAOA,MAAM,WAAWE,EAAoD,CACnE,OAAO,KAAK,QAAQ,eAAgB,CAClC,OAAQ,OACR,KAAMA,CACR,CAAC,CACH,CAKA,MAAM,UAAUA,EAA4C,CAC1D,OAAO,KAAK,QAAQ,cAAe,CACjC,OAAQ,OACR,KAAMA,CACR,CAAC,CACH,CAOA,MAAM,aAAaA,EAA8C,CAC/D,OAAO,KAAK,QAAQ,iBAAkB,CACpC,OAAQ,OACR,KAAMA,CACR,CAAC,CACH,CAKA,MAAM,cAAcA,EAAyD,CAC3E,OAAO,KAAK,QAAQ,kBAAmB,CACrC,OAAQ,OACR,KAAMA,CACR,CAAC,CACH,CAKA,MAAM,YAAYR,EAA8C,CAC9D,OAAO,KAAK,QAAQ,gBAAiB,CACnC,OAAQ,OACR,MAAAA,CACF,CAAC,CACH,CAOA,MAAM,eAAeA,EAAgE,CACnF,OAAO,KAAK,QAAQ,MAAO,CACzB,OAAQ,MACR,MAAAA,CACF,CAAC,CACH,CACF,ECxJA,IAAMS,EAA4B,IAKrBC,EAAN,KAAiB,CAStB,YAAYC,EAAoB,CARhCC,EAAA,KAAQ,UACRA,EAAA,KAAQ,WACRA,EAAA,KAAQ,OACRA,EAAA,KAAQ,SACRA,EAAA,KAAQ,YAAoC,IAAI,KAChDA,EAAA,KAAQ,eAAqD,MAC7DA,EAAA,KAAQ,cAAc,IAGpB,KAAK,OAAS,CACZ,OAAQD,EAAO,OACf,UAAWA,EAAO,UAClB,WAAYA,EAAO,WACnB,QAASA,EAAO,SAAW,eAC3B,MAAOA,EAAO,OAAS,GACvB,YAAaA,EAAO,aAAe,GACnC,iBAAkBA,EAAO,kBAAoBF,CAC/C,EAEA,KAAK,QAAUI,EAAc,KAAK,OAAO,OAAO,EAChD,KAAK,IAAM,IAAIC,EAAQ,KAAK,OAAO,OAAQ,KAAK,OAAO,KAAK,EAG5D,KAAK,MAAQ,CACX,gBAAiB,GACjB,UAAW,GACX,KAAM,KACN,YAAa,KACb,MAAO,IACT,CACF,CAKA,MAAM,YAA4B,CAChC,GAAI,MAAK,YAIT,MAAK,MAAM,0BAA0B,EAErC,GAAI,CACF,IAAMC,EAAc,KAAK,QAAQ,eAAe,EAC1CC,EAAO,KAAK,QAAQ,QAAkB,EACtCC,EAAS,KAAK,QAAQ,eAAe,EAE3C,GAAIF,GAAeC,GAAQC,EAAQ,CAEjC,IAAMC,EAAM,KAAK,MAAM,KAAK,IAAI,EAAI,GAAI,EACxC,GAAID,EAASC,EAAK,CAEhB,KAAK,YAAY,CACf,gBAAiB,GACjB,UAAW,GACX,KAAAF,EACA,YAAAD,EACA,MAAO,IACT,CAAC,EAGG,KAAK,OAAO,aACd,KAAK,gBAAgBE,EAASC,CAAG,EAGnC,KAAK,YAAc,GACnB,MACF,CAGA,IAAMC,EAAe,KAAK,QAAQ,gBAAgB,EAClD,GAAIA,EAAc,CAChB,MAAM,KAAK,eAAeA,CAAY,EACtC,KAAK,YAAc,GACnB,MACF,CACF,CAGA,KAAK,QAAQ,MAAM,EACnB,KAAK,YAAY,CACf,gBAAiB,GACjB,UAAW,GACX,KAAM,KACN,YAAa,KACb,MAAO,IACT,CAAC,CACH,OAASC,EAAO,CACd,KAAK,MAAM,wBAAyBA,CAAK,EACzC,KAAK,QAAQ,MAAM,EACnB,KAAK,YAAY,CACf,gBAAiB,GACjB,UAAW,GACX,KAAM,KACN,YAAa,KACb,MAAOC,EAAU,UAAUD,CAAc,CAC3C,CAAC,CACH,CAEA,KAAK,YAAc,GACrB,CAOA,UAAsB,CACpB,MAAO,CAAE,GAAG,KAAK,KAAM,CACzB,CAKA,mBAAmBE,EAA0C,CAC3D,YAAK,UAAU,IAAIA,CAAQ,EAE3BA,EAAS,KAAK,SAAS,CAAC,EACjB,IAAM,CACX,KAAK,UAAU,OAAOA,CAAQ,CAChC,CACF,CAKA,IAAI,iBAA2B,CAC7B,OAAO,KAAK,MAAM,eACpB,CAKA,IAAI,aAA+B,CACjC,OAAO,KAAK,MAAM,IACpB,CAKA,IAAI,aAA6B,CAC/B,OAAO,KAAK,MAAM,WACpB,CASA,MAAM,WAAWC,EAAiBC,EAAgB,QAA2B,CAC3E,KAAK,MAAM,sBAAuBD,EAASC,CAAI,EAE/C,IAAMC,EAAyB,CAC7B,QAAAF,EACA,KAAAC,EACA,UAAW,KAAK,OAAO,SACzB,EAGA,OADe,MAAM,KAAK,IAAI,WAAWC,CAAK,GAChC,IAChB,CAOA,MAAM,UAAUF,EAAiBG,EAAiC,CAChE,KAAK,MAAM,qBAAsBH,CAAO,EAExC,IAAME,EAAwB,CAC5B,QAAAF,EACA,KAAAG,EACA,UAAW,KAAK,OAAO,SACzB,EAEMC,EAAS,MAAM,KAAK,IAAI,UAAUF,CAAK,EAQ7C,KAAK,QAAQ,eAAeE,EAAO,WAAW,EAC9C,KAAK,QAAQ,QAAQA,EAAO,IAAI,EAGhC,IAAMV,EAAS,KAAK,MAAM,KAAK,IAAI,EAAI,GAAI,EAAI,MAAc,GAC7D,YAAK,QAAQ,eAAeA,CAAM,EAElC,KAAK,YAAY,CACf,gBAAiB,GACjB,UAAW,GACX,KAAMU,EAAO,KACb,YAAaA,EAAO,YACpB,MAAO,IACT,CAAC,EAEG,KAAK,OAAO,aACd,KAAK,gBAAgB,MAAc,EAAE,EAGhCA,EAAO,IAChB,CAQA,iBAAiBF,EAAoC,CACnD,KAAK,MAAM,mCAAoCA,EAAM,KAAK,GAAG,EAE7D,GAAM,CAAE,YAAAV,EAAa,KAAAC,EAAM,aAAAG,EAAc,UAAAS,EAAY,MAAc,EAAG,EAAIH,EAG1E,KAAK,QAAQ,eAAeV,CAAW,EACvC,KAAK,QAAQ,QAAQC,CAAI,EAErBG,GACF,KAAK,QAAQ,gBAAgBA,CAAY,EAG3C,IAAMF,EAAS,KAAK,MAAM,KAAK,IAAI,EAAI,GAAI,EAAIW,EAC/C,KAAK,QAAQ,eAAeX,CAAM,EAElC,KAAK,YAAY,CACf,gBAAiB,GACjB,UAAW,GACX,KAAAD,EACA,YAAAD,EACA,MAAO,IACT,CAAC,EAEG,KAAK,OAAO,aAAeI,GAC7B,KAAK,gBAAgBS,CAAS,CAElC,CAMA,IAAI,gBAAqC,CACvC,OAAO,KAAK,OAAO,UACrB,CAQA,MAAM,sBAAsBC,EAAyC,CACnE,KAAK,MAAM,2BAA2B,EAGtC,KAAK,YAAY,CACf,GAAG,KAAK,MACR,UAAW,GACX,MAAO,IACT,CAAC,EAED,GAAI,CAEF,IAAMC,EAAiB,MAAM,KAAK,IAAI,cAAc,CAAE,YAAaD,CAAM,CAAC,EAE1E,GAAI,CAACC,EAAe,OAAS,CAACA,EAAe,IAC3C,YAAK,MAAM,wCAAwC,EACnD,KAAK,YAAY,CACf,GAAG,KAAK,MACR,UAAW,EACb,CAAC,EACM,CAAE,QAAS,GAAO,MAAO,eAAgB,EAIlD,IAAMC,EAAa,MAAM,KAAK,IAAI,eAAeF,CAAK,EAGhDX,EAAM,KAAK,MAAM,KAAK,IAAI,EAAI,GAAI,EAClCU,EAAYE,EAAe,IAAMA,EAAe,IAAMZ,EAAM,MAAc,GAGhF,YAAK,iBAAiB,CACpB,YAAaW,EACb,KAAME,EAAW,KACjB,UAAAH,CACF,CAAC,EAED,KAAK,MAAM,uCAAwCG,EAAW,KAAK,GAAG,EAE/D,CAAE,QAAS,GAAM,KAAMA,EAAW,IAAK,CAChD,OAASX,EAAO,CACd,YAAK,MAAM,+BAAgCA,CAAK,EAChD,KAAK,YAAY,CACf,GAAG,KAAK,MACR,UAAW,GACX,MAAOC,EAAU,UAAUD,EAAgB,eAAe,CAC5D,CAAC,EAEM,CAAE,QAAS,GAAO,MADTA,aAAiB,MAAQA,EAAM,QAAU,6BACjB,CAC1C,CACF,CAOA,MAAM,UAAmC,CACvC,GAAI,CAAC,KAAK,MAAM,YACd,OAAO,KAIT,IAAMH,EAAS,KAAK,QAAQ,eAAe,EACrCC,EAAM,KAAK,MAAM,KAAK,IAAI,EAAI,GAAI,EAExC,GAAID,GAAUA,EAASC,EAAM,KAAK,OAAO,iBAAkB,CACzD,IAAMC,EAAe,KAAK,QAAQ,gBAAgB,EAC9CA,GACF,MAAM,KAAK,eAAeA,CAAY,CAE1C,CAEA,OAAO,KAAK,MAAM,WACpB,CAKA,MAAM,cAA8B,CAClC,IAAMA,EAAe,KAAK,QAAQ,gBAAgB,EAClD,GAAI,CAACA,EACH,MAAMa,EAAW,iBAAiB,EAEpC,MAAM,KAAK,eAAeb,CAAY,CACxC,CAKA,MAAM,SAAyB,CAU7B,GATA,KAAK,MAAM,aAAa,EAGpB,KAAK,eACP,aAAa,KAAK,YAAY,EAC9B,KAAK,aAAe,MAIlB,KAAK,MAAM,YACb,GAAI,CACF,MAAM,KAAK,IAAI,YAAY,KAAK,MAAM,WAAW,CACnD,OAASC,EAAO,CACd,KAAK,MAAM,gCAAiCA,CAAK,CACnD,CAIF,KAAK,QAAQ,MAAM,EAGnB,KAAK,YAAY,CACf,gBAAiB,GACjB,UAAW,GACX,KAAM,KACN,YAAa,KACb,MAAO,IACT,CAAC,CACH,CAOA,MAAM,gBAA2C,CAC/C,GAAI,CAAC,KAAK,MAAM,YACd,OAAO,KAGT,IAAMO,EAAS,MAAM,KAAK,IAAI,eAAe,KAAK,MAAM,WAAW,EAGnE,YAAK,QAAQ,QAAQA,EAAO,IAAI,EAChC,KAAK,YAAY,CACf,GAAG,KAAK,MACR,KAAMA,EAAO,IACf,CAAC,EAEMA,EAAO,IAChB,CAIQ,YAAYM,EAA2B,CAC7C,KAAK,MAAQA,EAEb,QAAWX,KAAY,KAAK,UAC1B,GAAI,CACFA,EAAS,KAAK,SAAS,CAAC,CAC1B,OAASF,EAAO,CACd,KAAK,MAAM,kBAAmBA,CAAK,CACrC,CAEJ,CAEA,MAAc,eAAeD,EAAqC,CAChE,KAAK,MAAM,kBAAkB,EAE7B,GAAI,CACF,IAAMQ,EAAS,MAAM,KAAK,IAAI,aAAa,CACzC,aAAAR,EACA,UAAW,KAAK,OAAO,SACzB,CAAC,EAGD,KAAK,QAAQ,eAAeQ,EAAO,WAAW,EAC9C,KAAK,QAAQ,gBAAgBA,EAAO,YAAY,EAEhD,IAAMV,EAAS,KAAK,MAAM,KAAK,IAAI,EAAI,GAAI,EAAIU,EAAO,UACtD,KAAK,QAAQ,eAAeV,CAAM,EAGlC,KAAK,YAAY,CACf,GAAG,KAAK,MACR,YAAaU,EAAO,YACpB,MAAO,IACT,CAAC,EAGG,KAAK,OAAO,aACd,KAAK,gBAAgBA,EAAO,SAAS,CAEzC,OAASP,EAAO,CACd,KAAK,MAAM,kBAAmBA,CAAK,EAEnC,KAAK,QAAQ,MAAM,EACnB,KAAK,YAAY,CACf,gBAAiB,GACjB,UAAW,GACX,KAAM,KACN,YAAa,KACb,MAAOC,EAAU,UAAUD,EAAgB,eAAe,CAC5D,CAAC,CACH,CACF,CAEQ,gBAAgBQ,EAAyB,CAC3C,KAAK,cACP,aAAa,KAAK,YAAY,EAIhC,IAAMM,EAAY,KAAK,IAAI,EAAGN,EAAY,KAAK,OAAO,gBAAgB,EAAI,IAE1E,KAAK,MAAM,yBAAyBM,EAAY,GAAI,GAAG,EAEvD,KAAK,aAAe,WAAW,IAAM,CACnC,IAAMf,EAAe,KAAK,QAAQ,gBAAgB,EAC9CA,GACF,KAAK,eAAeA,CAAY,CAEpC,EAAGe,CAAS,CACd,CAEQ,SAASC,EAAuB,CAClC,KAAK,OAAO,OACd,QAAQ,IAAI,eAAgB,GAAGA,CAAI,CAEvC,CACF,ECzaO,SAASC,GAAiBC,EAAgC,CAC/D,OAAO,IAAIC,EAAWD,CAAM,CAC9B","names":["AuthError","_AuthError","message","code","statusCode","originalError","__publicField","error","authErrors","AuthError","message","statusCode","parseApiError","response","body","errorBody","code","TOKEN_KEYS","isBrowser","WebStorage","type","__publicField","AuthError","token","expiry","user","MemoryStorage","createStorage","AuthApi","baseUrl","debug","__publicField","path","options","method","body","headers","token","url","reqHeaders","response","error","authErrors","responseBody","parseApiError","input","DEFAULT_REFRESH_THRESHOLD","AuthClient","config","__publicField","createStorage","AuthApi","accessToken","user","expiry","now","refreshToken","error","AuthError","listener","contact","type","input","code","result","expiresIn","token","validateResult","userResult","authErrors","newState","refreshIn","args","createAuthClient","config","AuthClient"]}
|