@genation/sdk 0.2.0 → 0.2.2

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/README.md CHANGED
@@ -48,9 +48,6 @@ const client = createClient({
48
48
  clientId: string; // Required
49
49
  clientSecret: string; // Required
50
50
  redirectUri: string; // Required
51
- scopes?: string[]; // Default: ['openid', 'profile', 'email']
52
- authUrl?: string; // Custom auth server URL
53
- storage?: 'memory' | 'localStorage' | 'sessionStorage';
54
51
  });
55
52
  ```
56
53
 
@@ -85,13 +82,13 @@ const url = await client.signIn();
85
82
  window.location.href = url;
86
83
  ```
87
84
 
88
- ### `client.handleCallback(code, state)`
85
+ ### `client.handleCallback(url)`
89
86
 
90
87
  Exchange authorization code for tokens.
91
88
 
92
89
  ```typescript
93
- const params = new URLSearchParams(window.location.search);
94
- await client.handleCallback(params.get("code")!, params.get("state")!);
90
+ const url = window.location.href;
91
+ await client.handleCallback(url);
95
92
  ```
96
93
 
97
94
  ### `client.getSession()`
@@ -118,11 +115,10 @@ interface Session {
118
115
  }
119
116
 
120
117
  interface User {
121
- id: string;
122
- email?: string;
118
+ sub: string; // user id
123
119
  name?: string;
124
- avatarUrl?: string;
125
- emailVerified?: boolean;
120
+ email?: string;
121
+ ...
126
122
  }
127
123
  ```
128
124
 
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});class d extends Error{code;cause;constructor(e,t,n){super(e),this.name="GenationError",this.code=t,this.cause=n}}class l extends d{constructor(e,t,n){super(e,t,n),this.name="AuthError"}static invalidGrant(e="Invalid authorization code or refresh token"){return new l(e,"invalid_grant")}static accessDenied(e="User denied access"){return new l(e,"access_denied")}static expiredToken(e="Token has expired"){return new l(e,"expired_token")}static invalidState(e="State mismatch, possible CSRF attack"){return new l(e,"invalid_state")}static pkceVerificationFailed(e="PKCE verification failed"){return new l(e,"pkce_verification_failed")}}class h extends d{status;constructor(e,t,n){super(e,"network_error",n),this.name="NetworkError",this.status=t}static fromResponse(e){return new h(`HTTP ${e.status}: ${e.statusText}`,e.status)}}class u extends d{constructor(e){super(e,"config_error"),this.name="ConfigError"}static missingField(e){return new u(`Missing required config field: ${e}`)}}class w{baseUrl;timeout;constructor(e){this.baseUrl=e.baseUrl.replace(/\/$/,""),this.timeout=e.timeout??3e4}async request(e,t={}){const{method:n="GET",headers:s={},body:i,params:a}=t;let c=`${this.baseUrl}${e}`;if(a){const o=new URLSearchParams(a);c+=`?${o.toString()}`}const S=new AbortController,T=setTimeout(()=>S.abort(),this.timeout);try{const o=await fetch(c,{method:n,headers:{"Content-Type":"application/json",...s},body:i?JSON.stringify(i):void 0,signal:S.signal});if(clearTimeout(T),!o.ok)throw h.fromResponse(o);return await o.json()}catch(o){throw clearTimeout(T),o instanceof h?o:o instanceof Error&&o.name==="AbortError"?new h("Request timeout",void 0,o):new h("Network request failed",void 0,o)}}async postForm(e,t,n={}){const s=`${this.baseUrl}${e}`,i=new AbortController,a=setTimeout(()=>i.abort(),this.timeout);try{const c=await fetch(s,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded",...n},body:new URLSearchParams(t).toString(),signal:i.signal});if(clearTimeout(a),!c.ok)throw h.fromResponse(c);return await c.json()}catch(c){throw clearTimeout(a),c instanceof h?c:new h("Network request failed",void 0,c)}}}function y(r){return btoa(String.fromCharCode(...r)).replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}function E(){const r=new Uint8Array(32);return crypto.getRandomValues(r),y(r)}async function U(r){const t=new TextEncoder().encode(r),n=await crypto.subtle.digest("SHA-256",t);return y(new Uint8Array(n))}async function I(){const r=E(),e=await U(r);return{codeVerifier:r,codeChallenge:e,codeChallengeMethod:"S256"}}function x(){const r=new Uint8Array(16);return crypto.getRandomValues(r),y(r)}const g="tokens",f="pkce",p="state";class A{storage;constructor(e){this.storage=e}async setTokens(e){await this.storage.set(g,JSON.stringify(e))}async getTokens(){const e=await this.storage.get(g);if(!e)return null;try{return JSON.parse(e)}catch{return null}}async clearTokens(){await this.storage.remove(g)}async isTokenExpired(){const e=await this.getTokens();if(!e)return!0;const t=e.issuedAt+e.expiresIn*1e3;return Date.now()>t-6e4}async setPKCE(e){await this.storage.set(f,e)}async consumePKCE(){const e=await this.storage.get(f);return e&&await this.storage.remove(f),e}async setState(e){await this.storage.set(p,e)}async consumeState(){const e=await this.storage.get(p);return e&&await this.storage.remove(p),e}async clearAll(){await this.storage.clear()}}const M="https://mnnoheowoowbtpuoguul.supabase.co/auth/v1";class K{config;http;tokenManager;constructor(e,t){this.config={clientId:e.clientId,clientSecret:e.clientSecret,redirectUri:e.redirectUri,scopes:e.scopes,authUrl:e.authUrl??M},this.http=new w({baseUrl:this.config.authUrl}),this.tokenManager=t}async getAuthorizationUrl(){const e=await I(),t=x();await this.tokenManager.setPKCE(e.codeVerifier),await this.tokenManager.setState(t);const n=new URLSearchParams({response_type:"code",client_id:this.config.clientId,redirect_uri:this.config.redirectUri,state:t,code_challenge:e.codeChallenge,code_challenge_method:e.codeChallengeMethod});return this.config.scopes&&this.config.scopes.length>0&&n.append("scope",this.config.scopes.join(" ")),`${this.config.authUrl}/oauth/authorize?${n.toString()}`}async exchangeCode(e,t){const n=await this.tokenManager.consumeState();if(!n||n!==t)throw l.invalidState();const s=await this.tokenManager.consumePKCE();if(!s)throw l.pkceVerificationFailed("Missing code verifier");const i=await this.http.postForm("/oauth/token",{grant_type:"authorization_code",code:e,redirect_uri:this.config.redirectUri,client_id:this.config.clientId,client_secret:this.config.clientSecret,code_verifier:s}),a=this.mapTokenResponse(i);return await this.tokenManager.setTokens(a),a}async refreshToken(){const e=await this.tokenManager.getTokens();if(!e?.refreshToken)throw l.invalidGrant("No refresh token available");const t=await this.http.postForm("/oauth/token",{grant_type:"refresh_token",refresh_token:e.refreshToken,client_id:this.config.clientId,client_secret:this.config.clientSecret}),n=this.mapTokenResponse(t);return await this.tokenManager.setTokens(n),n}async revokeToken(){const e=await this.tokenManager.getTokens();if(e)try{await this.http.postForm("/oauth/revoke",{token:e.accessToken,client_id:this.config.clientId,client_secret:this.config.clientSecret})}finally{await this.tokenManager.clearTokens()}}mapTokenResponse(e){return{accessToken:e.access_token,refreshToken:e.refresh_token,tokenType:e.token_type,expiresIn:e.expires_in,issuedAt:Date.now(),scope:e.scope}}}class b{store=new Map;async get(e){return this.store.get(e)??null}async set(e,t){this.store.set(e,t)}async remove(e){this.store.delete(e)}async clear(){this.store.clear()}}class m{prefix;constructor(e="genation"){this.prefix=e}getKey(e){return`${this.prefix}:${e}`}async get(e){return typeof window>"u"?null:localStorage.getItem(this.getKey(e))}async set(e,t){typeof window>"u"||localStorage.setItem(this.getKey(e),t)}async remove(e){typeof window>"u"||localStorage.removeItem(this.getKey(e))}async clear(){if(typeof window>"u")return;Object.keys(localStorage).filter(t=>t.startsWith(`${this.prefix}:`)).forEach(t=>localStorage.removeItem(t))}}class C{prefix;constructor(e="genation"){this.prefix=e}getKey(e){return`${this.prefix}:${e}`}async get(e){return typeof window>"u"?null:sessionStorage.getItem(this.getKey(e))}async set(e,t){typeof window>"u"||sessionStorage.setItem(this.getKey(e),t)}async remove(e){typeof window>"u"||sessionStorage.removeItem(this.getKey(e))}async clear(){if(typeof window>"u")return;Object.keys(sessionStorage).filter(t=>t.startsWith(`${this.prefix}:`)).forEach(t=>sessionStorage.removeItem(t))}}function _(r="localStorage"){switch(r){case"memory":return new b;case"localStorage":return new m;case"sessionStorage":return new C;default:return new m}}function k(r){return Array.isArray(r)?r.map(k):typeof r=="object"&&r!==null?Object.fromEntries(Object.entries(r).map(([e,t])=>[e.replace(/_([a-z])/g,(n,s)=>s.toUpperCase()),k(t)])):r}class v{oauth;tokenManager;http;httpServer;listeners=new Set;initialized=!1;constructor(e){this.validateConfig(e);const t=typeof e.storage=="object"?e.storage:_(e.storage);this.tokenManager=new A(t),this.oauth=new K(e,this.tokenManager),this.http=new w({baseUrl:e.authUrl??"https://mnnoheowoowbtpuoguul.supabase.co/auth/v1"}),this.httpServer=new w({baseUrl:"https://ff-api.genation.ai/api/v2/client"})}validateConfig(e){if(!e.clientId)throw u.missingField("clientId");if(!e.clientSecret)throw u.missingField("clientSecret");if(!e.redirectUri)throw u.missingField("redirectUri")}async emitAuthStateChange(e){const t=await this.getSession();this.listeners.forEach(n=>{try{n(e,t)}catch(s){console.error("Error in auth state change callback:",s)}})}onAuthStateChange(e){return this.listeners.add(e),this.initialized?setTimeout(()=>{this.emitAuthStateChange("INITIAL_SESSION")},0):(this.initialized=!0,setTimeout(()=>{this.emitAuthStateChange("INITIAL_SESSION")},0)),{subscription:{unsubscribe:()=>{this.listeners.delete(e)}}}}async signIn(){return this.oauth.getAuthorizationUrl()}async handleCallback(e,t){const n=await this.oauth.exchangeCode(e,t);try{const s=await this.fetchUser(n.accessToken);console.log("Debug: handleCallback fetched user:",s)}catch(s){console.error("Debug: handleCallback fetchUser failed:",s)}return await this.emitAuthStateChange("SIGNED_IN"),n}async getSession(){if(await this.tokenManager.isTokenExpired())try{await this.oauth.refreshToken()}catch{return null}const t=await this.tokenManager.getTokens();if(!t)return null;const n=await this.fetchUser(t.accessToken);return{accessToken:t.accessToken,refreshToken:t.refreshToken,expiresIn:t.expiresIn,expiresAt:t.issuedAt+t.expiresIn*1e3,user:n}}async getLicenses(e={}){const t=await this.getSession();if(!t)return null;const n=t.accessToken,{expiresAfter:s=new Date}=e,i=await this.httpServer.request("/licenses",{headers:{Authorization:`Bearer ${n}`},params:{expiresAfter:s.toISOString()}});if(!i.ok)return console.error("GenationClient: Error fetching licenses:",i.error),null;console.log("GenationClient: Response data:",i.data);const a=k(i.data);return console.log("GenationClient: Licenses:",a),a}async fetchUser(e){try{const t=await this.http.request("/oauth/userinfo",{headers:{Authorization:`Bearer ${e}`}});return{sub:t.sub,name:t.name,picture:t.picture,email:t.email,email_verified:t.email_verified,phone_number:t.phone_number,phone_number_verified:t.phone_number_verified}}catch(t){return console.error("GenationClient: Error fetching user:",t),null}}}function $(r){return new v(r)}exports.AuthError=l;exports.ConfigError=u;exports.GenationClient=v;exports.GenationError=d;exports.LocalStorage=m;exports.MemoryStorage=b;exports.NetworkError=h;exports.SessionStorage=C;exports.createClient=$;exports.createStorage=_;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});class d extends Error{code;cause;constructor(e,t,n){super(e),this.name="GenationError",this.code=t,this.cause=n}}class h extends d{constructor(e,t,n){super(e,t,n),this.name="AuthError"}static invalidGrant(e="Invalid authorization code or refresh token"){return new h(e,"invalid_grant")}static accessDenied(e="User denied access"){return new h(e,"access_denied")}static expiredToken(e="Token has expired"){return new h(e,"expired_token")}static invalidState(e="State mismatch, possible CSRF attack"){return new h(e,"invalid_state")}static pkceVerificationFailed(e="PKCE verification failed"){return new h(e,"pkce_verification_failed")}}class c extends d{status;constructor(e,t,n){super(e,"network_error",n),this.name="NetworkError",this.status=t}static fromResponse(e){return new c(`HTTP ${e.status}: ${e.statusText}`,e.status)}}class u extends d{constructor(e){super(e,"config_error"),this.name="ConfigError"}static missingField(e){return new u(`Missing required config field: ${e}`)}}class w{baseUrl;timeout;constructor(e){this.baseUrl=e.baseUrl.replace(/\/$/,""),this.timeout=e.timeout??3e4}async request(e,t={}){const{method:n="GET",headers:s={},body:i,params:l}=t;let a=`${this.baseUrl}${e}`;if(l){const o=new URLSearchParams(l);a+=`?${o.toString()}`}const S=new AbortController,T=setTimeout(()=>S.abort(),this.timeout);try{const o=await fetch(a,{method:n,headers:{"Content-Type":"application/json",...s},body:i?JSON.stringify(i):void 0,signal:S.signal});if(clearTimeout(T),!o.ok)throw c.fromResponse(o);return await o.json()}catch(o){throw clearTimeout(T),o instanceof c?o:o instanceof Error&&o.name==="AbortError"?new c("Request timeout",void 0,o):new c("Network request failed",void 0,o)}}async postForm(e,t,n={}){const s=`${this.baseUrl}${e}`,i=new AbortController,l=setTimeout(()=>i.abort(),this.timeout);try{const a=await fetch(s,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded",...n},body:new URLSearchParams(t).toString(),signal:i.signal});if(clearTimeout(l),!a.ok)throw c.fromResponse(a);return await a.json()}catch(a){throw clearTimeout(l),a instanceof c?a:new c("Network request failed",void 0,a)}}}function k(r){return btoa(String.fromCharCode(...r)).replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}function E(){const r=new Uint8Array(32);return crypto.getRandomValues(r),k(r)}async function I(r){const t=new TextEncoder().encode(r),n=await crypto.subtle.digest("SHA-256",t);return k(new Uint8Array(n))}async function U(){const r=E(),e=await I(r);return{codeVerifier:r,codeChallenge:e,codeChallengeMethod:"S256"}}function x(){const r=new Uint8Array(16);return crypto.getRandomValues(r),k(r)}const g="tokens",f="pkce",p="state";class A{storage;constructor(e){this.storage=e}async setTokens(e){await this.storage.set(g,JSON.stringify(e))}async getTokens(){const e=await this.storage.get(g);if(!e)return null;try{return JSON.parse(e)}catch{return null}}async clearTokens(){await this.storage.remove(g)}async isTokenExpired(){const e=await this.getTokens();if(!e)return!0;const t=e.issuedAt+e.expiresIn*1e3;return Date.now()>t-6e4}async setPKCE(e){await this.storage.set(f,e)}async consumePKCE(){const e=await this.storage.get(f);return e&&await this.storage.remove(f),e}async setState(e){await this.storage.set(p,e)}async consumeState(){const e=await this.storage.get(p);return e&&await this.storage.remove(p),e}async clearAll(){await this.storage.clear()}}const M="https://mnnoheowoowbtpuoguul.supabase.co/auth/v1";class K{config;http;tokenManager;constructor(e,t){this.config={clientId:e.clientId,clientSecret:e.clientSecret,redirectUri:e.redirectUri,scopes:e.scopes,authUrl:e.authUrl??M},this.http=new w({baseUrl:this.config.authUrl}),this.tokenManager=t}async getAuthorizationUrl(){const e=await U(),t=x();await this.tokenManager.setPKCE(e.codeVerifier),await this.tokenManager.setState(t);const n=new URLSearchParams({response_type:"code",client_id:this.config.clientId,redirect_uri:this.config.redirectUri,state:t,code_challenge:e.codeChallenge,code_challenge_method:e.codeChallengeMethod});return this.config.scopes&&this.config.scopes.length>0&&n.append("scope",this.config.scopes.join(" ")),`${this.config.authUrl}/oauth/authorize?${n.toString()}`}async exchangeCode(e,t){const n=await this.tokenManager.consumeState();if(!n||n!==t)throw h.invalidState();const s=await this.tokenManager.consumePKCE();if(!s)throw h.pkceVerificationFailed("Missing code verifier");const i=await this.http.postForm("/oauth/token",{grant_type:"authorization_code",code:e,redirect_uri:this.config.redirectUri,client_id:this.config.clientId,client_secret:this.config.clientSecret,code_verifier:s}),l=this.mapTokenResponse(i);return await this.tokenManager.setTokens(l),l}async refreshToken(){const e=await this.tokenManager.getTokens();if(!e?.refreshToken)throw h.invalidGrant("No refresh token available");const t=await this.http.postForm("/oauth/token",{grant_type:"refresh_token",refresh_token:e.refreshToken,client_id:this.config.clientId,client_secret:this.config.clientSecret}),n=this.mapTokenResponse(t);return await this.tokenManager.setTokens(n),n}async revokeToken(){const e=await this.tokenManager.getTokens();if(e)try{await this.http.postForm("/oauth/revoke",{token:e.accessToken,client_id:this.config.clientId,client_secret:this.config.clientSecret})}finally{await this.tokenManager.clearTokens()}}mapTokenResponse(e){return{accessToken:e.access_token,refreshToken:e.refresh_token,tokenType:e.token_type,expiresIn:e.expires_in,issuedAt:Date.now(),scope:e.scope}}}class b{store=new Map;async get(e){return this.store.get(e)??null}async set(e,t){this.store.set(e,t)}async remove(e){this.store.delete(e)}async clear(){this.store.clear()}}class m{prefix;constructor(e="genation"){this.prefix=e}getKey(e){return`${this.prefix}:${e}`}async get(e){return typeof window>"u"?null:localStorage.getItem(this.getKey(e))}async set(e,t){typeof window>"u"||localStorage.setItem(this.getKey(e),t)}async remove(e){typeof window>"u"||localStorage.removeItem(this.getKey(e))}async clear(){if(typeof window>"u")return;Object.keys(localStorage).filter(t=>t.startsWith(`${this.prefix}:`)).forEach(t=>localStorage.removeItem(t))}}class _{prefix;constructor(e="genation"){this.prefix=e}getKey(e){return`${this.prefix}:${e}`}async get(e){return typeof window>"u"?null:sessionStorage.getItem(this.getKey(e))}async set(e,t){typeof window>"u"||sessionStorage.setItem(this.getKey(e),t)}async remove(e){typeof window>"u"||sessionStorage.removeItem(this.getKey(e))}async clear(){if(typeof window>"u")return;Object.keys(sessionStorage).filter(t=>t.startsWith(`${this.prefix}:`)).forEach(t=>sessionStorage.removeItem(t))}}function v(r="localStorage"){switch(r){case"memory":return new b;case"localStorage":return new m;case"sessionStorage":return new _;default:return new m}}function y(r){return Array.isArray(r)?r.map(y):typeof r=="object"&&r!==null?Object.fromEntries(Object.entries(r).map(([e,t])=>[e.replace(/_([a-z])/g,(n,s)=>s.toUpperCase()),y(t)])):r}class C{oauth;tokenManager;http;httpServer;listeners=new Set;initialized=!1;constructor(e){this.validateConfig(e);const t=typeof e.storage=="object"?e.storage:v(e.storage);this.tokenManager=new A(t),this.oauth=new K(e,this.tokenManager),this.http=new w({baseUrl:e.authUrl??"https://mnnoheowoowbtpuoguul.supabase.co/auth/v1"}),this.httpServer=new w({baseUrl:"https://ff-api.genation.ai/api/v2/client"})}validateConfig(e){if(!e.clientId)throw u.missingField("clientId");if(!e.clientSecret)throw u.missingField("clientSecret");if(!e.redirectUri)throw u.missingField("redirectUri")}async emitAuthStateChange(e){const t=await this.getSession();this.listeners.forEach(n=>{try{n(e,t)}catch(s){console.error("Error in auth state change callback:",s)}})}onAuthStateChange(e){return this.listeners.add(e),this.initialized?setTimeout(()=>{this.emitAuthStateChange("INITIAL_SESSION")},0):(this.initialized=!0,setTimeout(()=>{this.emitAuthStateChange("INITIAL_SESSION")},0)),{subscription:{unsubscribe:()=>{this.listeners.delete(e)}}}}async signIn(){return this.oauth.getAuthorizationUrl()}async handleCallback(e){const t=new URLSearchParams(e),n=t.get("code"),s=t.get("state");if(!n||!s)throw new Error("Missing code or state");const i=await this.oauth.exchangeCode(n,s);return await this.emitAuthStateChange("SIGNED_IN"),i}async getSession(){if(await this.tokenManager.isTokenExpired())try{await this.oauth.refreshToken()}catch{return null}const t=await this.tokenManager.getTokens();if(!t)return null;const n=await this.fetchUser(t.accessToken);return{accessToken:t.accessToken,refreshToken:t.refreshToken,expiresIn:t.expiresIn,expiresAt:t.issuedAt+t.expiresIn*1e3,user:n}}async getLicenses(e={}){const t=await this.getSession();if(!t)return null;const n=t.accessToken,{expiresAfter:s=new Date}=e,i=await this.httpServer.request("/licenses",{headers:{Authorization:`Bearer ${n}`},params:{expiresAfter:s.toISOString()}});return i.ok?y(i.data):(console.error("GenationClient: Error fetching licenses:",i.error),null)}async fetchUser(e){try{const t=await this.http.request("/oauth/userinfo",{headers:{Authorization:`Bearer ${e}`}});return{sub:t.sub,name:t.name,picture:t.picture,email:t.email,email_verified:t.email_verified,phone_number:t.phone_number,phone_number_verified:t.phone_number_verified}}catch(t){return console.error("GenationClient: Error fetching user:",t),null}}}function $(r){return new C(r)}exports.AuthError=h;exports.ConfigError=u;exports.GenationClient=C;exports.GenationError=d;exports.LocalStorage=m;exports.MemoryStorage=b;exports.NetworkError=c;exports.SessionStorage=_;exports.createClient=$;exports.createStorage=v;
2
2
  //# sourceMappingURL=genation.cjs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"genation.cjs.js","sources":["../src/http/errors.ts","../src/http/client.ts","../src/auth/pkce.ts","../src/auth/token-manager.ts","../src/auth/oauth.ts","../src/storage/memory.ts","../src/storage/local-storage.ts","../src/storage/session-storage.ts","../src/storage/index.ts","../src/utils/converter.ts","../src/client.ts"],"sourcesContent":["/**\r\n * Base error class for Genation SDK\r\n */\r\nexport class GenationError extends Error {\r\n public code: string;\r\n public cause?: unknown;\r\n\r\n constructor(message: string, code: string, cause?: unknown) {\r\n super(message);\r\n this.name = \"GenationError\";\r\n this.code = code;\r\n this.cause = cause;\r\n }\r\n}\r\n\r\n/**\r\n * Authentication-related errors\r\n */\r\nexport class AuthError extends GenationError {\r\n constructor(message: string, code: string, cause?: unknown) {\r\n super(message, code, cause);\r\n this.name = \"AuthError\";\r\n }\r\n\r\n static invalidGrant(\r\n message = \"Invalid authorization code or refresh token\",\r\n ) {\r\n return new AuthError(message, \"invalid_grant\");\r\n }\r\n\r\n static accessDenied(message = \"User denied access\") {\r\n return new AuthError(message, \"access_denied\");\r\n }\r\n\r\n static expiredToken(message = \"Token has expired\") {\r\n return new AuthError(message, \"expired_token\");\r\n }\r\n\r\n static invalidState(message = \"State mismatch, possible CSRF attack\") {\r\n return new AuthError(message, \"invalid_state\");\r\n }\r\n\r\n static pkceVerificationFailed(message = \"PKCE verification failed\") {\r\n return new AuthError(message, \"pkce_verification_failed\");\r\n }\r\n}\r\n\r\n/**\r\n * Network-related errors\r\n */\r\nexport class NetworkError extends GenationError {\r\n public status?: number;\r\n\r\n constructor(message: string, status?: number, cause?: unknown) {\r\n super(message, \"network_error\", cause);\r\n this.name = \"NetworkError\";\r\n this.status = status;\r\n }\r\n\r\n static fromResponse(response: Response) {\r\n return new NetworkError(\r\n `HTTP ${response.status}: ${response.statusText}`,\r\n response.status,\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Configuration-related errors\r\n */\r\nexport class ConfigError extends GenationError {\r\n constructor(message: string) {\r\n super(message, \"config_error\");\r\n this.name = \"ConfigError\";\r\n }\r\n\r\n static missingField(field: string) {\r\n return new ConfigError(`Missing required config field: ${field}`);\r\n }\r\n}\r\n","import { NetworkError } from \"./errors\";\r\n\r\nexport interface HttpClientConfig {\r\n baseUrl: string;\r\n timeout?: number;\r\n}\r\n\r\nexport interface RequestOptions {\r\n method?: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\";\r\n headers?: Record<string, string>;\r\n body?: unknown;\r\n params?: Record<string, string>;\r\n}\r\n\r\n/**\r\n * Simple HTTP client wrapper around fetch\r\n */\r\nexport class HttpClient {\r\n private baseUrl: string;\r\n private timeout: number;\r\n\r\n constructor(config: HttpClientConfig) {\r\n this.baseUrl = config.baseUrl.replace(/\\/$/, \"\");\r\n this.timeout = config.timeout ?? 30000;\r\n }\r\n\r\n /**\r\n * Make an HTTP request\r\n */\r\n async request<T>(\r\n endpoint: string,\r\n options: RequestOptions = {},\r\n ): Promise<T> {\r\n const { method = \"GET\", headers = {}, body, params } = options;\r\n\r\n // Build URL with query params\r\n let url = `${this.baseUrl}${endpoint}`;\r\n if (params) {\r\n const searchParams = new URLSearchParams(params);\r\n url += `?${searchParams.toString()}`;\r\n }\r\n\r\n // Setup abort controller for timeout\r\n const controller = new AbortController();\r\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\r\n\r\n try {\r\n const response = await fetch(url, {\r\n method,\r\n headers: {\r\n \"Content-Type\": \"application/json\",\r\n ...headers,\r\n },\r\n body: body ? JSON.stringify(body) : undefined,\r\n signal: controller.signal,\r\n });\r\n\r\n clearTimeout(timeoutId);\r\n\r\n if (!response.ok) {\r\n throw NetworkError.fromResponse(response);\r\n }\r\n\r\n return await response.json();\r\n } catch (error) {\r\n clearTimeout(timeoutId);\r\n\r\n if (error instanceof NetworkError) {\r\n throw error;\r\n }\r\n\r\n if (error instanceof Error && error.name === \"AbortError\") {\r\n throw new NetworkError(\"Request timeout\", undefined, error);\r\n }\r\n\r\n throw new NetworkError(\"Network request failed\", undefined, error);\r\n }\r\n }\r\n\r\n /**\r\n * POST request with form data (for OAuth token exchange)\r\n */\r\n async postForm<T>(\r\n endpoint: string,\r\n data: Record<string, string>,\r\n headers: Record<string, string> = {},\r\n ): Promise<T> {\r\n const url = `${this.baseUrl}${endpoint}`;\r\n const controller = new AbortController();\r\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\r\n\r\n try {\r\n const response = await fetch(url, {\r\n method: \"POST\",\r\n headers: {\r\n \"Content-Type\": \"application/x-www-form-urlencoded\",\r\n ...headers,\r\n },\r\n body: new URLSearchParams(data).toString(),\r\n signal: controller.signal,\r\n });\r\n\r\n clearTimeout(timeoutId);\r\n\r\n if (!response.ok) {\r\n throw NetworkError.fromResponse(response);\r\n }\r\n\r\n return await response.json();\r\n } catch (error) {\r\n clearTimeout(timeoutId);\r\n\r\n if (error instanceof NetworkError) {\r\n throw error;\r\n }\r\n\r\n throw new NetworkError(\"Network request failed\", undefined, error);\r\n }\r\n }\r\n}\r\n\r\nexport { AuthError, ConfigError, GenationError, NetworkError } from \"./errors\";\r\n","import type { PKCEChallenge } from \"../types\";\r\n\r\n/**\r\n * Base64URL encode a buffer (matches Supabase implementation)\r\n */\r\nfunction base64URLEncode(buffer: Uint8Array): string {\r\n return btoa(String.fromCharCode(...buffer))\r\n .replace(/\\+/g, \"-\")\r\n .replace(/\\//g, \"_\")\r\n .replace(/=/g, \"\");\r\n}\r\n\r\n/**\r\n * Generate a random code verifier (43-128 characters)\r\n * Matches Supabase implementation\r\n */\r\nfunction generateCodeVerifier(): string {\r\n const array = new Uint8Array(32);\r\n crypto.getRandomValues(array);\r\n return base64URLEncode(array);\r\n}\r\n\r\n/**\r\n * Create code challenge from verifier using SHA-256\r\n * Matches Supabase implementation\r\n */\r\nasync function generateCodeChallenge(verifier: string): Promise<string> {\r\n const encoder = new TextEncoder();\r\n const data = encoder.encode(verifier);\r\n const hash = await crypto.subtle.digest(\"SHA-256\", data);\r\n return base64URLEncode(new Uint8Array(hash));\r\n}\r\n\r\n/**\r\n * Generate PKCE code verifier and challenge pair\r\n * Uses S256 method as required by OAuth 2.1\r\n */\r\nexport async function generatePKCE(): Promise<PKCEChallenge> {\r\n const codeVerifier = generateCodeVerifier();\r\n const codeChallenge = await generateCodeChallenge(codeVerifier);\r\n\r\n return {\r\n codeVerifier,\r\n codeChallenge,\r\n codeChallengeMethod: \"S256\",\r\n };\r\n}\r\n\r\n/**\r\n * Generate random state parameter for CSRF protection\r\n */\r\nexport function generateState(): string {\r\n const array = new Uint8Array(16);\r\n crypto.getRandomValues(array);\r\n return base64URLEncode(array);\r\n}\r\n","import type { TokenSet, TokenStorage } from \"../types\";\r\n\r\nconst TOKEN_KEY = \"tokens\";\r\nconst PKCE_KEY = \"pkce\";\r\nconst STATE_KEY = \"state\";\r\n\r\n/**\r\n * Manages token lifecycle: storage, retrieval, refresh\r\n */\r\nexport class TokenManager {\r\n private storage: TokenStorage;\r\n\r\n constructor(storage: TokenStorage) {\r\n this.storage = storage;\r\n }\r\n\r\n /**\r\n * Store token set\r\n */\r\n async setTokens(tokens: TokenSet): Promise<void> {\r\n await this.storage.set(TOKEN_KEY, JSON.stringify(tokens));\r\n }\r\n\r\n /**\r\n * Get stored tokens\r\n */\r\n async getTokens(): Promise<TokenSet | null> {\r\n const data = await this.storage.get(TOKEN_KEY);\r\n if (!data) return null;\r\n\r\n try {\r\n return JSON.parse(data) as TokenSet;\r\n } catch {\r\n return null;\r\n }\r\n }\r\n\r\n /**\r\n * Clear stored tokens\r\n */\r\n async clearTokens(): Promise<void> {\r\n await this.storage.remove(TOKEN_KEY);\r\n }\r\n\r\n /**\r\n * Check if access token is expired\r\n */\r\n async isTokenExpired(): Promise<boolean> {\r\n const tokens = await this.getTokens();\r\n if (!tokens) return true;\r\n\r\n const expiresAt = tokens.issuedAt + tokens.expiresIn * 1000;\r\n // Consider expired if less than 60 seconds remaining\r\n return Date.now() > expiresAt - 60000;\r\n }\r\n\r\n /**\r\n * Store PKCE verifier for later validation\r\n */\r\n async setPKCE(codeVerifier: string): Promise<void> {\r\n await this.storage.set(PKCE_KEY, codeVerifier);\r\n }\r\n\r\n /**\r\n * Get and clear stored PKCE verifier\r\n */\r\n async consumePKCE(): Promise<string | null> {\r\n const verifier = await this.storage.get(PKCE_KEY);\r\n if (verifier) {\r\n await this.storage.remove(PKCE_KEY);\r\n }\r\n return verifier;\r\n }\r\n\r\n /**\r\n * Store state for CSRF validation\r\n */\r\n async setState(state: string): Promise<void> {\r\n await this.storage.set(STATE_KEY, state);\r\n }\r\n\r\n /**\r\n * Get and clear stored state\r\n */\r\n async consumeState(): Promise<string | null> {\r\n const state = await this.storage.get(STATE_KEY);\r\n if (state) {\r\n await this.storage.remove(STATE_KEY);\r\n }\r\n return state;\r\n }\r\n\r\n /**\r\n * Clear all auth-related data\r\n */\r\n async clearAll(): Promise<void> {\r\n await this.storage.clear();\r\n }\r\n}\r\n","import type { GenationConfig, TokenSet } from \"../types\";\r\nimport { AuthError, HttpClient } from \"../http\";\r\nimport { generatePKCE, generateState } from \"./pkce\";\r\nimport { TokenManager } from \"./token-manager\";\r\n\r\nconst DEFAULT_AUTH_URL = \"https://mnnoheowoowbtpuoguul.supabase.co/auth/v1\";\r\n\r\ninterface TokenResponse {\r\n access_token: string;\r\n refresh_token?: string;\r\n token_type: string;\r\n expires_in: number;\r\n scope?: string;\r\n}\r\n\r\n/**\r\n * OAuth 2.1 handler with PKCE support\r\n */\r\nexport class OAuth2Handler {\r\n private config:\r\n & Required<\r\n Pick<GenationConfig, \"clientId\" | \"clientSecret\" | \"redirectUri\">\r\n >\r\n & Pick<GenationConfig, \"scopes\" | \"authUrl\">;\r\n private http: HttpClient;\r\n private tokenManager: TokenManager;\r\n\r\n constructor(\r\n config: GenationConfig,\r\n tokenManager: TokenManager,\r\n ) {\r\n this.config = {\r\n clientId: config.clientId,\r\n clientSecret: config.clientSecret,\r\n redirectUri: config.redirectUri,\r\n scopes: config.scopes,\r\n authUrl: config.authUrl ?? DEFAULT_AUTH_URL,\r\n };\r\n this.http = new HttpClient({ baseUrl: this.config.authUrl! });\r\n this.tokenManager = tokenManager;\r\n }\r\n\r\n /**\r\n * Generate authorization URL for OAuth flow\r\n * Stores PKCE verifier and state for later validation\r\n */\r\n async getAuthorizationUrl(): Promise<string> {\r\n const pkce = await generatePKCE();\r\n const state = generateState();\r\n\r\n // Store for later validation\r\n await this.tokenManager.setPKCE(pkce.codeVerifier);\r\n await this.tokenManager.setState(state);\r\n\r\n const params = new URLSearchParams({\r\n response_type: \"code\",\r\n client_id: this.config.clientId,\r\n redirect_uri: this.config.redirectUri,\r\n state,\r\n code_challenge: pkce.codeChallenge,\r\n code_challenge_method: pkce.codeChallengeMethod,\r\n });\r\n\r\n if (this.config.scopes && this.config.scopes.length > 0) {\r\n params.append(\"scope\", this.config.scopes.join(\" \"));\r\n }\r\n\r\n return `${this.config.authUrl}/oauth/authorize?${params.toString()}`;\r\n }\r\n\r\n /**\r\n * Exchange authorization code for tokens\r\n */\r\n async exchangeCode(code: string, state: string): Promise<TokenSet> {\r\n // Validate state\r\n const storedState = await this.tokenManager.consumeState();\r\n if (!storedState || storedState !== state) {\r\n throw AuthError.invalidState();\r\n }\r\n\r\n // Get PKCE verifier\r\n const codeVerifier = await this.tokenManager.consumePKCE();\r\n if (!codeVerifier) {\r\n throw AuthError.pkceVerificationFailed(\"Missing code verifier\");\r\n }\r\n\r\n // Exchange code for tokens\r\n const response = await this.http.postForm<TokenResponse>(\r\n \"/oauth/token\",\r\n {\r\n grant_type: \"authorization_code\",\r\n code,\r\n redirect_uri: this.config.redirectUri,\r\n client_id: this.config.clientId,\r\n client_secret: this.config.clientSecret,\r\n code_verifier: codeVerifier,\r\n },\r\n );\r\n\r\n const tokens = this.mapTokenResponse(response);\r\n await this.tokenManager.setTokens(tokens);\r\n\r\n return tokens;\r\n }\r\n\r\n /**\r\n * Refresh access token using refresh token\r\n */\r\n async refreshToken(): Promise<TokenSet> {\r\n const currentTokens = await this.tokenManager.getTokens();\r\n if (!currentTokens?.refreshToken) {\r\n throw AuthError.invalidGrant(\"No refresh token available\");\r\n }\r\n\r\n const response = await this.http.postForm<TokenResponse>(\r\n \"/oauth/token\",\r\n {\r\n grant_type: \"refresh_token\",\r\n refresh_token: currentTokens.refreshToken,\r\n client_id: this.config.clientId,\r\n client_secret: this.config.clientSecret,\r\n },\r\n );\r\n\r\n const tokens = this.mapTokenResponse(response);\r\n await this.tokenManager.setTokens(tokens);\r\n\r\n return tokens;\r\n }\r\n\r\n /**\r\n * Revoke current tokens\r\n */\r\n async revokeToken(): Promise<void> {\r\n const tokens = await this.tokenManager.getTokens();\r\n if (!tokens) return;\r\n\r\n try {\r\n await this.http.postForm(\"/oauth/revoke\", {\r\n token: tokens.accessToken,\r\n client_id: this.config.clientId,\r\n client_secret: this.config.clientSecret,\r\n });\r\n } finally {\r\n await this.tokenManager.clearTokens();\r\n }\r\n }\r\n\r\n /**\r\n * Map OAuth token response to TokenSet\r\n */\r\n private mapTokenResponse(response: TokenResponse): TokenSet {\r\n return {\r\n accessToken: response.access_token,\r\n refreshToken: response.refresh_token,\r\n tokenType: response.token_type,\r\n expiresIn: response.expires_in,\r\n issuedAt: Date.now(),\r\n scope: response.scope,\r\n };\r\n }\r\n}\r\n","import type { TokenStorage } from \"../types\";\r\n\r\n/**\r\n * In-memory storage implementation\r\n * Tokens are lost when page refreshes\r\n */\r\nexport class MemoryStorage implements TokenStorage {\r\n private store = new Map<string, string>();\r\n\r\n async get(key: string): Promise<string | null> {\r\n return this.store.get(key) ?? null;\r\n }\r\n\r\n async set(key: string, value: string): Promise<void> {\r\n this.store.set(key, value);\r\n }\r\n\r\n async remove(key: string): Promise<void> {\r\n this.store.delete(key);\r\n }\r\n\r\n async clear(): Promise<void> {\r\n this.store.clear();\r\n }\r\n}\r\n","import type { TokenStorage } from \"../types\";\r\n\r\n/**\r\n * Browser localStorage implementation\r\n * Tokens persist across browser sessions\r\n */\r\nexport class LocalStorage implements TokenStorage {\r\n private prefix: string;\r\n\r\n constructor(prefix = \"genation\") {\r\n this.prefix = prefix;\r\n }\r\n\r\n private getKey(key: string): string {\r\n return `${this.prefix}:${key}`;\r\n }\r\n\r\n async get(key: string): Promise<string | null> {\r\n if (typeof window === \"undefined\") return null;\r\n return localStorage.getItem(this.getKey(key));\r\n }\r\n\r\n async set(key: string, value: string): Promise<void> {\r\n if (typeof window === \"undefined\") return;\r\n localStorage.setItem(this.getKey(key), value);\r\n }\r\n\r\n async remove(key: string): Promise<void> {\r\n if (typeof window === \"undefined\") return;\r\n localStorage.removeItem(this.getKey(key));\r\n }\r\n\r\n async clear(): Promise<void> {\r\n if (typeof window === \"undefined\") return;\r\n const keys = Object.keys(localStorage).filter((k) =>\r\n k.startsWith(`${this.prefix}:`)\r\n );\r\n keys.forEach((k) => localStorage.removeItem(k));\r\n }\r\n}\r\n","import type { TokenStorage } from \"../types\";\r\n\r\n/**\r\n * Browser sessionStorage implementation\r\n * Tokens persist until browser tab is closed\r\n */\r\nexport class SessionStorage implements TokenStorage {\r\n private prefix: string;\r\n\r\n constructor(prefix = \"genation\") {\r\n this.prefix = prefix;\r\n }\r\n\r\n private getKey(key: string): string {\r\n return `${this.prefix}:${key}`;\r\n }\r\n\r\n async get(key: string): Promise<string | null> {\r\n if (typeof window === \"undefined\") return null;\r\n return sessionStorage.getItem(this.getKey(key));\r\n }\r\n\r\n async set(key: string, value: string): Promise<void> {\r\n if (typeof window === \"undefined\") return;\r\n sessionStorage.setItem(this.getKey(key), value);\r\n }\r\n\r\n async remove(key: string): Promise<void> {\r\n if (typeof window === \"undefined\") return;\r\n sessionStorage.removeItem(this.getKey(key));\r\n }\r\n\r\n async clear(): Promise<void> {\r\n if (typeof window === \"undefined\") return;\r\n const keys = Object.keys(sessionStorage).filter((k) =>\r\n k.startsWith(`${this.prefix}:`)\r\n );\r\n keys.forEach((k) => sessionStorage.removeItem(k));\r\n }\r\n}\r\n","/**\r\n * @fileoverview Storage factory and implementations\r\n * @module storage\r\n */\r\n\r\nimport type { StorageType, TokenStorage } from \"../types\";\r\nimport { MemoryStorage } from \"./memory\";\r\nimport { LocalStorage } from \"./local-storage\";\r\nimport { SessionStorage } from \"./session-storage\";\r\n\r\nexport { MemoryStorage } from \"./memory\";\r\nexport { LocalStorage } from \"./local-storage\";\r\nexport { SessionStorage } from \"./session-storage\";\r\n\r\n/**\r\n * Create a storage instance based on type\r\n *\r\n * @param type - Storage type to create\r\n * @returns Storage implementation\r\n *\r\n * @example\r\n * ```typescript\r\n * const storage = createStorage('localStorage');\r\n * await storage.set('key', 'value');\r\n * ```\r\n */\r\nexport function createStorage(\r\n type: StorageType = \"localStorage\",\r\n): TokenStorage {\r\n switch (type) {\r\n case \"memory\":\r\n return new MemoryStorage();\r\n case \"localStorage\":\r\n return new LocalStorage();\r\n case \"sessionStorage\":\r\n return new SessionStorage();\r\n default:\r\n return new LocalStorage();\r\n }\r\n}\r\n","// Function to convert snake_case to camelCase, handles arrays and objects recursively\r\nexport function snakeToCamel(data: any): any {\r\n if (Array.isArray(data)) {\r\n return data.map(snakeToCamel);\r\n } else if (typeof data === \"object\" && data !== null) {\r\n return Object.fromEntries(\r\n Object.entries(data).map(([key, value]) => [\r\n key.replace(/_([a-z])/g, (_, c) => c.toUpperCase()),\r\n snakeToCamel(value)\r\n ])\r\n );\r\n }\r\n return data;\r\n}","/**\r\n * @fileoverview Main Genation SDK client\r\n * @module client\r\n */\r\n\r\nimport type {\r\n AuthEvent,\r\n AuthStateChangeCallback,\r\n GenationConfig,\r\n Session,\r\n Subscription,\r\n TokenSet,\r\n TokenStorage,\r\n User,\r\n} from \"./types\";\r\nimport { OAuth2Handler, TokenManager } from \"./auth\";\r\nimport { createStorage } from \"./storage\";\r\nimport { ConfigError, HttpClient } from \"./http\";\r\nimport type { License, LicenseResponse } from \"./types/server/license\";\r\nimport type { ApiResponse } from \"./types/server/api-response\";\r\nimport { snakeToCamel } from \"./utils/converter\";\r\n\r\n// Re-export types for convenience\r\nexport type { AuthEvent, AuthStateChangeCallback, Session, Subscription };\r\n\r\n/**\r\n * Main Genation SDK client\r\n *\r\n * OAuth 2.1 authentication client for Genation platform.\r\n * Supports PKCE flow and automatic token refresh.\r\n *\r\n * @example\r\n * ```typescript\r\n * import { createClient } from 'genation';\r\n *\r\n * const client = createClient({\r\n * clientId: 'your-client-id',\r\n * clientSecret: 'your-client-secret',\r\n * redirectUri: 'http://localhost:3000/callback'\r\n * });\r\n *\r\n * // Listen to auth state changes\r\n * const { subscription } = client.onAuthStateChange((event, session) => {\r\n * if (event === 'SIGNED_IN') {\r\n * console.log('User signed in:', session?.user);\r\n * }\r\n * });\r\n *\r\n * // Start login flow\r\n * window.location.href = await client.signIn();\r\n * ```\r\n */\r\nexport class GenationClient {\r\n private oauth: OAuth2Handler;\r\n private tokenManager: TokenManager;\r\n private http: HttpClient;\r\n private httpServer: HttpClient;\r\n private listeners: Set<AuthStateChangeCallback> = new Set();\r\n private initialized = false;\r\n\r\n constructor(config: GenationConfig) {\r\n this.validateConfig(config);\r\n\r\n const storage: TokenStorage = typeof config.storage === \"object\"\r\n ? (config.storage as unknown as TokenStorage)\r\n : createStorage(config.storage);\r\n\r\n this.tokenManager = new TokenManager(storage);\r\n this.oauth = new OAuth2Handler(config, this.tokenManager);\r\n this.http = new HttpClient({\r\n baseUrl: config.authUrl ??\r\n \"https://mnnoheowoowbtpuoguul.supabase.co/auth/v1\",\r\n });\r\n this.httpServer = new HttpClient({\r\n baseUrl: \"https://ff-api.genation.ai/api/v2/client\"\r\n });\r\n }\r\n\r\n private validateConfig(config: GenationConfig): void {\r\n if (!config.clientId) throw ConfigError.missingField(\"clientId\");\r\n if (!config.clientSecret) {\r\n throw ConfigError.missingField(\"clientSecret\");\r\n }\r\n if (!config.redirectUri) throw ConfigError.missingField(\"redirectUri\");\r\n }\r\n\r\n /**\r\n * Emit auth state change event to all listeners\r\n */\r\n private async emitAuthStateChange(event: AuthEvent): Promise<void> {\r\n const session = await this.getSession();\r\n this.listeners.forEach((callback) => {\r\n try {\r\n callback(event, session);\r\n } catch (error) {\r\n console.error(\"Error in auth state change callback:\", error);\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Listen to authentication state changes\r\n *\r\n * Register a callback that fires when:\r\n * - `INITIAL_SESSION`: On first subscription, with current session state\r\n * - `SIGNED_IN`: User successfully authenticated\r\n * - `SIGNED_OUT`: User logged out or session expired\r\n * - `TOKEN_REFRESHED`: Access token was automatically refreshed\r\n *\r\n * @param callback - Function called on each auth state change\r\n * @returns Object containing subscription with `unsubscribe()` method\r\n *\r\n * @example\r\n * ```typescript\r\n * const { subscription } = client.onAuthStateChange((event, session) => {\r\n * console.log('Auth event:', event);\r\n *\r\n * if (event === 'INITIAL_SESSION') {\r\n * // Check if user was previously logged in\r\n * if (session) {\r\n * console.log('Welcome back!', session.user);\r\n * }\r\n * } else if (event === 'SIGNED_IN') {\r\n * // User just signed in\r\n * console.log('Signed in:', session?.user);\r\n * } else if (event === 'SIGNED_OUT') {\r\n * // Clear app state, redirect to login\r\n * console.log('Signed out');\r\n * }\r\n * });\r\n *\r\n * // Cleanup when component unmounts\r\n * subscription.unsubscribe();\r\n * ```\r\n */\r\n onAuthStateChange(\r\n callback: AuthStateChangeCallback,\r\n ): { subscription: Subscription } {\r\n this.listeners.add(callback);\r\n\r\n // Emit INITIAL_SESSION on first subscription\r\n if (!this.initialized) {\r\n this.initialized = true;\r\n setTimeout(() => {\r\n this.emitAuthStateChange(\"INITIAL_SESSION\");\r\n }, 0);\r\n } else {\r\n // For subsequent subscriptions, also emit current state\r\n setTimeout(() => {\r\n this.emitAuthStateChange(\"INITIAL_SESSION\");\r\n }, 0);\r\n }\r\n\r\n return {\r\n subscription: {\r\n unsubscribe: () => {\r\n this.listeners.delete(callback);\r\n },\r\n },\r\n };\r\n }\r\n\r\n /**\r\n * Start OAuth sign-in flow\r\n *\r\n * Generates authorization URL with PKCE challenge.\r\n * Redirect user to this URL to start authentication.\r\n *\r\n * @returns Authorization URL to redirect user to\r\n *\r\n * @example\r\n * ```typescript\r\n * async function handleLogin() {\r\n * const url = await client.signIn();\r\n * window.location.href = url;\r\n * }\r\n * ```\r\n */\r\n async signIn(): Promise<string> {\r\n return this.oauth.getAuthorizationUrl();\r\n }\r\n\r\n /**\r\n * Handle OAuth callback after user authentication\r\n *\r\n * Call this on your redirect URI page to exchange\r\n * the authorization code for access tokens.\r\n * Triggers `SIGNED_IN` event on success.\r\n *\r\n * @param code - Authorization code from URL query params\r\n * @param state - State parameter for CSRF validation\r\n * @returns Token set with access and refresh tokens\r\n * @throws {AuthError} If state mismatch or code exchange fails\r\n *\r\n * @example\r\n * ```typescript\r\n * // On your /callback page\r\n * async function handleCallback() {\r\n * const params = new URLSearchParams(window.location.search);\r\n * const code = params.get('code');\r\n * const state = params.get('state');\r\n *\r\n * if (code && state) {\r\n * await client.handleCallback(code, state);\r\n * // onAuthStateChange will fire with SIGNED_IN event\r\n * }\r\n * }\r\n * ```\r\n */\r\n async handleCallback(code: string, state: string): Promise<TokenSet> {\r\n const tokens = await this.oauth.exchangeCode(code, state);\r\n\r\n // Debug: Fetch user immediately to check if it works\r\n try {\r\n const user = await this.fetchUser(tokens.accessToken);\r\n console.log(\"Debug: handleCallback fetched user:\", user);\r\n } catch (e) {\r\n console.error(\"Debug: handleCallback fetchUser failed:\", e);\r\n }\r\n\r\n await this.emitAuthStateChange(\"SIGNED_IN\");\r\n return tokens;\r\n }\r\n\r\n // /**\r\n // * Sign out and revoke tokens\r\n // *\r\n // * Clears local session and revokes tokens on server.\r\n // * Triggers `SIGNED_OUT` event for all listeners.\r\n // *\r\n // * @example\r\n // * ```typescript\r\n // * async function handleLogout() {\r\n // * await client.signOut();\r\n // * // onAuthStateChange will fire with SIGNED_OUT event\r\n // * }\r\n // * ```\r\n // */\r\n // async signOut(): Promise<void> {\r\n // await this.oauth.revokeToken();\r\n // await this.emitAuthStateChange(\"SIGNED_OUT\");\r\n // }\r\n\r\n /**\r\n * Get current session\r\n *\r\n * Returns session with access token and user info.\r\n * Automatically refreshes token if expired.\r\n *\r\n * @returns Current session or null if not authenticated\r\n *\r\n * @example\r\n * ```typescript\r\n * const session = await client.getSession();\r\n * if (session) {\r\n * console.log('Logged in as:', session.user?.email);\r\n *\r\n * // Use access token for API calls\r\n * fetch('/api/data', {\r\n * headers: { Authorization: `Bearer ${session.accessToken}` }\r\n * });\r\n * }\r\n * ```\r\n */\r\n async getSession(): Promise<Session | null> {\r\n const isExpired = await this.tokenManager.isTokenExpired();\r\n\r\n if (isExpired) {\r\n try {\r\n await this.oauth.refreshToken();\r\n } catch {\r\n return null;\r\n }\r\n }\r\n\r\n const tokens = await this.tokenManager.getTokens();\r\n if (!tokens) return null;\r\n\r\n const user = await this.fetchUser(tokens.accessToken);\r\n\r\n return {\r\n accessToken: tokens.accessToken,\r\n refreshToken: tokens.refreshToken,\r\n expiresIn: tokens.expiresIn,\r\n expiresAt: tokens.issuedAt + tokens.expiresIn * 1000,\r\n user,\r\n };\r\n }\r\n /**\r\n * Get licenses\r\n * @param accessToken - The access token to use for the request\r\n * @param options - The options for the request\r\n * @param options.expiresAfter - Query licenses that are expired after the given date, default set to today to get all valid licenses (unexpired licenses)\r\n * @returns The licenses\r\n */\r\n async getLicenses(options: { expiresAfter?: Date } = {}): Promise<License[] | null> {\r\n const session = await this.getSession();\r\n if (!session) {\r\n return null;\r\n }\r\n const accessToken = session.accessToken;\r\n const { expiresAfter = new Date() } = options;\r\n const response = await this.httpServer.request<ApiResponse<LicenseResponse[]>>(\"/licenses\", {\r\n headers: { Authorization: `Bearer ${accessToken}` },\r\n params: { expiresAfter: expiresAfter.toISOString() }\r\n });\r\n if (!response.ok) {\r\n console.error(\"GenationClient: Error fetching licenses:\", response.error);\r\n return null;\r\n }\r\n console.log(\"GenationClient: Response data:\", response.data);\r\n const licenses: License[] = snakeToCamel(response.data);\r\n console.log(\"GenationClient: Licenses:\", licenses);\r\n return licenses;\r\n }\r\n /**\r\n * Fetch user info from auth server\r\n */\r\n private async fetchUser(accessToken: string): Promise<User | null> {\r\n try {\r\n // Use standard OIDC UserInfo endpoint\r\n // https://supabase.com/docs/guides/auth/oauth-server/oauth-flows#userinfo-endpoint\r\n const response = await this.http.request<{\r\n sub: string;\r\n email?: string;\r\n name?: string;\r\n picture?: string;\r\n email_verified?: boolean;\r\n phone_number?: string;\r\n phone_number_verified?: boolean;\r\n }>(\"/oauth/userinfo\", {\r\n headers: { Authorization: `Bearer ${accessToken}` },\r\n });\r\n\r\n return {\r\n sub: response.sub,\r\n name: response.name,\r\n picture: response.picture,\r\n email: response.email,\r\n email_verified: response.email_verified,\r\n phone_number: response.phone_number,\r\n phone_number_verified: response.phone_number_verified,\r\n };\r\n } catch (error) {\r\n console.error(\"GenationClient: Error fetching user:\", error);\r\n return null;\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Create a new Genation client instance\r\n *\r\n * Factory function for creating SDK client with configuration.\r\n *\r\n * @param config - Client configuration options\r\n * @returns Configured GenationClient instance\r\n *\r\n * @example\r\n * ```typescript\r\n * import { createClient } from 'genation';\r\n *\r\n * const client = createClient({\r\n * clientId: 'your-client-id',\r\n * clientSecret: 'your-client-secret',\r\n * redirectUri: 'http://localhost:3000/callback',\r\n * // Optional\r\n * scopes: ['openid', 'profile', 'email'],\r\n * storage: 'localStorage',\r\n * });\r\n * ```\r\n */\r\nexport function createClient(config: GenationConfig): GenationClient {\r\n return new GenationClient(config);\r\n}\r\n"],"names":["GenationError","message","code","cause","AuthError","NetworkError","status","response","ConfigError","field","HttpClient","config","endpoint","options","method","headers","body","params","url","searchParams","controller","timeoutId","error","data","base64URLEncode","buffer","generateCodeVerifier","array","generateCodeChallenge","verifier","hash","generatePKCE","codeVerifier","codeChallenge","generateState","TOKEN_KEY","PKCE_KEY","STATE_KEY","TokenManager","storage","tokens","expiresAt","state","DEFAULT_AUTH_URL","OAuth2Handler","tokenManager","pkce","storedState","currentTokens","MemoryStorage","key","value","LocalStorage","prefix","k","SessionStorage","createStorage","type","snakeToCamel","_","c","GenationClient","event","session","callback","user","e","accessToken","expiresAfter","licenses","createClient"],"mappings":"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"}
1
+ {"version":3,"file":"genation.cjs.js","sources":["../src/http/errors.ts","../src/http/client.ts","../src/auth/pkce.ts","../src/auth/token-manager.ts","../src/auth/oauth.ts","../src/storage/memory.ts","../src/storage/local-storage.ts","../src/storage/session-storage.ts","../src/storage/index.ts","../src/utils/converter.ts","../src/client.ts"],"sourcesContent":["/**\r\n * Base error class for Genation SDK\r\n */\r\nexport class GenationError extends Error {\r\n public code: string;\r\n public cause?: unknown;\r\n\r\n constructor(message: string, code: string, cause?: unknown) {\r\n super(message);\r\n this.name = \"GenationError\";\r\n this.code = code;\r\n this.cause = cause;\r\n }\r\n}\r\n\r\n/**\r\n * Authentication-related errors\r\n */\r\nexport class AuthError extends GenationError {\r\n constructor(message: string, code: string, cause?: unknown) {\r\n super(message, code, cause);\r\n this.name = \"AuthError\";\r\n }\r\n\r\n static invalidGrant(\r\n message = \"Invalid authorization code or refresh token\",\r\n ) {\r\n return new AuthError(message, \"invalid_grant\");\r\n }\r\n\r\n static accessDenied(message = \"User denied access\") {\r\n return new AuthError(message, \"access_denied\");\r\n }\r\n\r\n static expiredToken(message = \"Token has expired\") {\r\n return new AuthError(message, \"expired_token\");\r\n }\r\n\r\n static invalidState(message = \"State mismatch, possible CSRF attack\") {\r\n return new AuthError(message, \"invalid_state\");\r\n }\r\n\r\n static pkceVerificationFailed(message = \"PKCE verification failed\") {\r\n return new AuthError(message, \"pkce_verification_failed\");\r\n }\r\n}\r\n\r\n/**\r\n * Network-related errors\r\n */\r\nexport class NetworkError extends GenationError {\r\n public status?: number;\r\n\r\n constructor(message: string, status?: number, cause?: unknown) {\r\n super(message, \"network_error\", cause);\r\n this.name = \"NetworkError\";\r\n this.status = status;\r\n }\r\n\r\n static fromResponse(response: Response) {\r\n return new NetworkError(\r\n `HTTP ${response.status}: ${response.statusText}`,\r\n response.status,\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Configuration-related errors\r\n */\r\nexport class ConfigError extends GenationError {\r\n constructor(message: string) {\r\n super(message, \"config_error\");\r\n this.name = \"ConfigError\";\r\n }\r\n\r\n static missingField(field: string) {\r\n return new ConfigError(`Missing required config field: ${field}`);\r\n }\r\n}\r\n","import { NetworkError } from \"./errors\";\r\n\r\nexport interface HttpClientConfig {\r\n baseUrl: string;\r\n timeout?: number;\r\n}\r\n\r\nexport interface RequestOptions {\r\n method?: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\";\r\n headers?: Record<string, string>;\r\n body?: unknown;\r\n params?: Record<string, string>;\r\n}\r\n\r\n/**\r\n * Simple HTTP client wrapper around fetch\r\n */\r\nexport class HttpClient {\r\n private baseUrl: string;\r\n private timeout: number;\r\n\r\n constructor(config: HttpClientConfig) {\r\n this.baseUrl = config.baseUrl.replace(/\\/$/, \"\");\r\n this.timeout = config.timeout ?? 30000;\r\n }\r\n\r\n /**\r\n * Make an HTTP request\r\n */\r\n async request<T>(\r\n endpoint: string,\r\n options: RequestOptions = {},\r\n ): Promise<T> {\r\n const { method = \"GET\", headers = {}, body, params } = options;\r\n\r\n // Build URL with query params\r\n let url = `${this.baseUrl}${endpoint}`;\r\n if (params) {\r\n const searchParams = new URLSearchParams(params);\r\n url += `?${searchParams.toString()}`;\r\n }\r\n\r\n // Setup abort controller for timeout\r\n const controller = new AbortController();\r\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\r\n\r\n try {\r\n const response = await fetch(url, {\r\n method,\r\n headers: {\r\n \"Content-Type\": \"application/json\",\r\n ...headers,\r\n },\r\n body: body ? JSON.stringify(body) : undefined,\r\n signal: controller.signal,\r\n });\r\n\r\n clearTimeout(timeoutId);\r\n\r\n if (!response.ok) {\r\n throw NetworkError.fromResponse(response);\r\n }\r\n\r\n return await response.json();\r\n } catch (error) {\r\n clearTimeout(timeoutId);\r\n\r\n if (error instanceof NetworkError) {\r\n throw error;\r\n }\r\n\r\n if (error instanceof Error && error.name === \"AbortError\") {\r\n throw new NetworkError(\"Request timeout\", undefined, error);\r\n }\r\n\r\n throw new NetworkError(\"Network request failed\", undefined, error);\r\n }\r\n }\r\n\r\n /**\r\n * POST request with form data (for OAuth token exchange)\r\n */\r\n async postForm<T>(\r\n endpoint: string,\r\n data: Record<string, string>,\r\n headers: Record<string, string> = {},\r\n ): Promise<T> {\r\n const url = `${this.baseUrl}${endpoint}`;\r\n const controller = new AbortController();\r\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\r\n\r\n try {\r\n const response = await fetch(url, {\r\n method: \"POST\",\r\n headers: {\r\n \"Content-Type\": \"application/x-www-form-urlencoded\",\r\n ...headers,\r\n },\r\n body: new URLSearchParams(data).toString(),\r\n signal: controller.signal,\r\n });\r\n\r\n clearTimeout(timeoutId);\r\n\r\n if (!response.ok) {\r\n throw NetworkError.fromResponse(response);\r\n }\r\n\r\n return await response.json();\r\n } catch (error) {\r\n clearTimeout(timeoutId);\r\n\r\n if (error instanceof NetworkError) {\r\n throw error;\r\n }\r\n\r\n throw new NetworkError(\"Network request failed\", undefined, error);\r\n }\r\n }\r\n}\r\n\r\nexport { AuthError, ConfigError, GenationError, NetworkError } from \"./errors\";\r\n","import type { PKCEChallenge } from \"../types\";\r\n\r\n/**\r\n * Base64URL encode a buffer (matches Supabase implementation)\r\n */\r\nfunction base64URLEncode(buffer: Uint8Array): string {\r\n return btoa(String.fromCharCode(...buffer))\r\n .replace(/\\+/g, \"-\")\r\n .replace(/\\//g, \"_\")\r\n .replace(/=/g, \"\");\r\n}\r\n\r\n/**\r\n * Generate a random code verifier (43-128 characters)\r\n * Matches Supabase implementation\r\n */\r\nfunction generateCodeVerifier(): string {\r\n const array = new Uint8Array(32);\r\n crypto.getRandomValues(array);\r\n return base64URLEncode(array);\r\n}\r\n\r\n/**\r\n * Create code challenge from verifier using SHA-256\r\n * Matches Supabase implementation\r\n */\r\nasync function generateCodeChallenge(verifier: string): Promise<string> {\r\n const encoder = new TextEncoder();\r\n const data = encoder.encode(verifier);\r\n const hash = await crypto.subtle.digest(\"SHA-256\", data);\r\n return base64URLEncode(new Uint8Array(hash));\r\n}\r\n\r\n/**\r\n * Generate PKCE code verifier and challenge pair\r\n * Uses S256 method as required by OAuth 2.1\r\n */\r\nexport async function generatePKCE(): Promise<PKCEChallenge> {\r\n const codeVerifier = generateCodeVerifier();\r\n const codeChallenge = await generateCodeChallenge(codeVerifier);\r\n\r\n return {\r\n codeVerifier,\r\n codeChallenge,\r\n codeChallengeMethod: \"S256\",\r\n };\r\n}\r\n\r\n/**\r\n * Generate random state parameter for CSRF protection\r\n */\r\nexport function generateState(): string {\r\n const array = new Uint8Array(16);\r\n crypto.getRandomValues(array);\r\n return base64URLEncode(array);\r\n}\r\n","import type { TokenSet, TokenStorage } from \"../types\";\r\n\r\nconst TOKEN_KEY = \"tokens\";\r\nconst PKCE_KEY = \"pkce\";\r\nconst STATE_KEY = \"state\";\r\n\r\n/**\r\n * Manages token lifecycle: storage, retrieval, refresh\r\n */\r\nexport class TokenManager {\r\n private storage: TokenStorage;\r\n\r\n constructor(storage: TokenStorage) {\r\n this.storage = storage;\r\n }\r\n\r\n /**\r\n * Store token set\r\n */\r\n async setTokens(tokens: TokenSet): Promise<void> {\r\n await this.storage.set(TOKEN_KEY, JSON.stringify(tokens));\r\n }\r\n\r\n /**\r\n * Get stored tokens\r\n */\r\n async getTokens(): Promise<TokenSet | null> {\r\n const data = await this.storage.get(TOKEN_KEY);\r\n if (!data) return null;\r\n\r\n try {\r\n return JSON.parse(data) as TokenSet;\r\n } catch {\r\n return null;\r\n }\r\n }\r\n\r\n /**\r\n * Clear stored tokens\r\n */\r\n async clearTokens(): Promise<void> {\r\n await this.storage.remove(TOKEN_KEY);\r\n }\r\n\r\n /**\r\n * Check if access token is expired\r\n */\r\n async isTokenExpired(): Promise<boolean> {\r\n const tokens = await this.getTokens();\r\n if (!tokens) return true;\r\n\r\n const expiresAt = tokens.issuedAt + tokens.expiresIn * 1000;\r\n // Consider expired if less than 60 seconds remaining\r\n return Date.now() > expiresAt - 60000;\r\n }\r\n\r\n /**\r\n * Store PKCE verifier for later validation\r\n */\r\n async setPKCE(codeVerifier: string): Promise<void> {\r\n await this.storage.set(PKCE_KEY, codeVerifier);\r\n }\r\n\r\n /**\r\n * Get and clear stored PKCE verifier\r\n */\r\n async consumePKCE(): Promise<string | null> {\r\n const verifier = await this.storage.get(PKCE_KEY);\r\n if (verifier) {\r\n await this.storage.remove(PKCE_KEY);\r\n }\r\n return verifier;\r\n }\r\n\r\n /**\r\n * Store state for CSRF validation\r\n */\r\n async setState(state: string): Promise<void> {\r\n await this.storage.set(STATE_KEY, state);\r\n }\r\n\r\n /**\r\n * Get and clear stored state\r\n */\r\n async consumeState(): Promise<string | null> {\r\n const state = await this.storage.get(STATE_KEY);\r\n if (state) {\r\n await this.storage.remove(STATE_KEY);\r\n }\r\n return state;\r\n }\r\n\r\n /**\r\n * Clear all auth-related data\r\n */\r\n async clearAll(): Promise<void> {\r\n await this.storage.clear();\r\n }\r\n}\r\n","import type { GenationConfig, TokenSet } from \"../types\";\r\nimport { AuthError, HttpClient } from \"../http\";\r\nimport { generatePKCE, generateState } from \"./pkce\";\r\nimport { TokenManager } from \"./token-manager\";\r\n\r\nconst DEFAULT_AUTH_URL = \"https://mnnoheowoowbtpuoguul.supabase.co/auth/v1\";\r\n\r\ninterface TokenResponse {\r\n access_token: string;\r\n refresh_token?: string;\r\n token_type: string;\r\n expires_in: number;\r\n scope?: string;\r\n}\r\n\r\n/**\r\n * OAuth 2.1 handler with PKCE support\r\n */\r\nexport class OAuth2Handler {\r\n private config:\r\n & Required<\r\n Pick<GenationConfig, \"clientId\" | \"clientSecret\" | \"redirectUri\">\r\n >\r\n & Pick<GenationConfig, \"scopes\" | \"authUrl\">;\r\n private http: HttpClient;\r\n private tokenManager: TokenManager;\r\n\r\n constructor(\r\n config: GenationConfig,\r\n tokenManager: TokenManager,\r\n ) {\r\n this.config = {\r\n clientId: config.clientId,\r\n clientSecret: config.clientSecret,\r\n redirectUri: config.redirectUri,\r\n scopes: config.scopes,\r\n authUrl: config.authUrl ?? DEFAULT_AUTH_URL,\r\n };\r\n this.http = new HttpClient({ baseUrl: this.config.authUrl! });\r\n this.tokenManager = tokenManager;\r\n }\r\n\r\n /**\r\n * Generate authorization URL for OAuth flow\r\n * Stores PKCE verifier and state for later validation\r\n */\r\n async getAuthorizationUrl(): Promise<string> {\r\n const pkce = await generatePKCE();\r\n const state = generateState();\r\n\r\n // Store for later validation\r\n await this.tokenManager.setPKCE(pkce.codeVerifier);\r\n await this.tokenManager.setState(state);\r\n\r\n const params = new URLSearchParams({\r\n response_type: \"code\",\r\n client_id: this.config.clientId,\r\n redirect_uri: this.config.redirectUri,\r\n state,\r\n code_challenge: pkce.codeChallenge,\r\n code_challenge_method: pkce.codeChallengeMethod,\r\n });\r\n\r\n if (this.config.scopes && this.config.scopes.length > 0) {\r\n params.append(\"scope\", this.config.scopes.join(\" \"));\r\n }\r\n\r\n return `${this.config.authUrl}/oauth/authorize?${params.toString()}`;\r\n }\r\n\r\n /**\r\n * Exchange authorization code for tokens\r\n */\r\n async exchangeCode(code: string, state: string): Promise<TokenSet> {\r\n // Validate state\r\n const storedState = await this.tokenManager.consumeState();\r\n if (!storedState || storedState !== state) {\r\n throw AuthError.invalidState();\r\n }\r\n\r\n // Get PKCE verifier\r\n const codeVerifier = await this.tokenManager.consumePKCE();\r\n if (!codeVerifier) {\r\n throw AuthError.pkceVerificationFailed(\"Missing code verifier\");\r\n }\r\n\r\n // Exchange code for tokens\r\n const response = await this.http.postForm<TokenResponse>(\r\n \"/oauth/token\",\r\n {\r\n grant_type: \"authorization_code\",\r\n code,\r\n redirect_uri: this.config.redirectUri,\r\n client_id: this.config.clientId,\r\n client_secret: this.config.clientSecret,\r\n code_verifier: codeVerifier,\r\n },\r\n );\r\n\r\n const tokens = this.mapTokenResponse(response);\r\n await this.tokenManager.setTokens(tokens);\r\n\r\n return tokens;\r\n }\r\n\r\n /**\r\n * Refresh access token using refresh token\r\n */\r\n async refreshToken(): Promise<TokenSet> {\r\n const currentTokens = await this.tokenManager.getTokens();\r\n if (!currentTokens?.refreshToken) {\r\n throw AuthError.invalidGrant(\"No refresh token available\");\r\n }\r\n\r\n const response = await this.http.postForm<TokenResponse>(\r\n \"/oauth/token\",\r\n {\r\n grant_type: \"refresh_token\",\r\n refresh_token: currentTokens.refreshToken,\r\n client_id: this.config.clientId,\r\n client_secret: this.config.clientSecret,\r\n },\r\n );\r\n\r\n const tokens = this.mapTokenResponse(response);\r\n await this.tokenManager.setTokens(tokens);\r\n\r\n return tokens;\r\n }\r\n\r\n /**\r\n * Revoke current tokens\r\n */\r\n async revokeToken(): Promise<void> {\r\n const tokens = await this.tokenManager.getTokens();\r\n if (!tokens) return;\r\n\r\n try {\r\n await this.http.postForm(\"/oauth/revoke\", {\r\n token: tokens.accessToken,\r\n client_id: this.config.clientId,\r\n client_secret: this.config.clientSecret,\r\n });\r\n } finally {\r\n await this.tokenManager.clearTokens();\r\n }\r\n }\r\n\r\n /**\r\n * Map OAuth token response to TokenSet\r\n */\r\n private mapTokenResponse(response: TokenResponse): TokenSet {\r\n return {\r\n accessToken: response.access_token,\r\n refreshToken: response.refresh_token,\r\n tokenType: response.token_type,\r\n expiresIn: response.expires_in,\r\n issuedAt: Date.now(),\r\n scope: response.scope,\r\n };\r\n }\r\n}\r\n","import type { TokenStorage } from \"../types\";\r\n\r\n/**\r\n * In-memory storage implementation\r\n * Tokens are lost when page refreshes\r\n */\r\nexport class MemoryStorage implements TokenStorage {\r\n private store = new Map<string, string>();\r\n\r\n async get(key: string): Promise<string | null> {\r\n return this.store.get(key) ?? null;\r\n }\r\n\r\n async set(key: string, value: string): Promise<void> {\r\n this.store.set(key, value);\r\n }\r\n\r\n async remove(key: string): Promise<void> {\r\n this.store.delete(key);\r\n }\r\n\r\n async clear(): Promise<void> {\r\n this.store.clear();\r\n }\r\n}\r\n","import type { TokenStorage } from \"../types\";\r\n\r\n/**\r\n * Browser localStorage implementation\r\n * Tokens persist across browser sessions\r\n */\r\nexport class LocalStorage implements TokenStorage {\r\n private prefix: string;\r\n\r\n constructor(prefix = \"genation\") {\r\n this.prefix = prefix;\r\n }\r\n\r\n private getKey(key: string): string {\r\n return `${this.prefix}:${key}`;\r\n }\r\n\r\n async get(key: string): Promise<string | null> {\r\n if (typeof window === \"undefined\") return null;\r\n return localStorage.getItem(this.getKey(key));\r\n }\r\n\r\n async set(key: string, value: string): Promise<void> {\r\n if (typeof window === \"undefined\") return;\r\n localStorage.setItem(this.getKey(key), value);\r\n }\r\n\r\n async remove(key: string): Promise<void> {\r\n if (typeof window === \"undefined\") return;\r\n localStorage.removeItem(this.getKey(key));\r\n }\r\n\r\n async clear(): Promise<void> {\r\n if (typeof window === \"undefined\") return;\r\n const keys = Object.keys(localStorage).filter((k) =>\r\n k.startsWith(`${this.prefix}:`)\r\n );\r\n keys.forEach((k) => localStorage.removeItem(k));\r\n }\r\n}\r\n","import type { TokenStorage } from \"../types\";\r\n\r\n/**\r\n * Browser sessionStorage implementation\r\n * Tokens persist until browser tab is closed\r\n */\r\nexport class SessionStorage implements TokenStorage {\r\n private prefix: string;\r\n\r\n constructor(prefix = \"genation\") {\r\n this.prefix = prefix;\r\n }\r\n\r\n private getKey(key: string): string {\r\n return `${this.prefix}:${key}`;\r\n }\r\n\r\n async get(key: string): Promise<string | null> {\r\n if (typeof window === \"undefined\") return null;\r\n return sessionStorage.getItem(this.getKey(key));\r\n }\r\n\r\n async set(key: string, value: string): Promise<void> {\r\n if (typeof window === \"undefined\") return;\r\n sessionStorage.setItem(this.getKey(key), value);\r\n }\r\n\r\n async remove(key: string): Promise<void> {\r\n if (typeof window === \"undefined\") return;\r\n sessionStorage.removeItem(this.getKey(key));\r\n }\r\n\r\n async clear(): Promise<void> {\r\n if (typeof window === \"undefined\") return;\r\n const keys = Object.keys(sessionStorage).filter((k) =>\r\n k.startsWith(`${this.prefix}:`)\r\n );\r\n keys.forEach((k) => sessionStorage.removeItem(k));\r\n }\r\n}\r\n","/**\r\n * @fileoverview Storage factory and implementations\r\n * @module storage\r\n */\r\n\r\nimport type { StorageType, TokenStorage } from \"../types\";\r\nimport { MemoryStorage } from \"./memory\";\r\nimport { LocalStorage } from \"./local-storage\";\r\nimport { SessionStorage } from \"./session-storage\";\r\n\r\nexport { MemoryStorage } from \"./memory\";\r\nexport { LocalStorage } from \"./local-storage\";\r\nexport { SessionStorage } from \"./session-storage\";\r\n\r\n/**\r\n * Create a storage instance based on type\r\n *\r\n * @param type - Storage type to create\r\n * @returns Storage implementation\r\n *\r\n * @example\r\n * ```typescript\r\n * const storage = createStorage('localStorage');\r\n * await storage.set('key', 'value');\r\n * ```\r\n */\r\nexport function createStorage(\r\n type: StorageType = \"localStorage\",\r\n): TokenStorage {\r\n switch (type) {\r\n case \"memory\":\r\n return new MemoryStorage();\r\n case \"localStorage\":\r\n return new LocalStorage();\r\n case \"sessionStorage\":\r\n return new SessionStorage();\r\n default:\r\n return new LocalStorage();\r\n }\r\n}\r\n","// Function to convert snake_case to camelCase, handles arrays and objects recursively\r\nexport function snakeToCamel(data: any): any {\r\n if (Array.isArray(data)) {\r\n return data.map(snakeToCamel);\r\n } else if (typeof data === \"object\" && data !== null) {\r\n return Object.fromEntries(\r\n Object.entries(data).map(([key, value]) => [\r\n key.replace(/_([a-z])/g, (_, c) => c.toUpperCase()),\r\n snakeToCamel(value)\r\n ])\r\n );\r\n }\r\n return data;\r\n}","/**\r\n * @fileoverview Main Genation SDK client\r\n * @module client\r\n */\r\n\r\nimport type {\r\n AuthEvent,\r\n AuthStateChangeCallback,\r\n GenationConfig,\r\n Session,\r\n Subscription,\r\n TokenSet,\r\n TokenStorage,\r\n User,\r\n} from \"./types\";\r\nimport { OAuth2Handler, TokenManager } from \"./auth\";\r\nimport { createStorage } from \"./storage\";\r\nimport { ConfigError, HttpClient } from \"./http\";\r\nimport type { License, LicenseResponse } from \"./types/server/license\";\r\nimport type { ApiResponse } from \"./types/server/api-response\";\r\nimport { snakeToCamel } from \"./utils/converter\";\r\n\r\n// Re-export types for convenience\r\nexport type { AuthEvent, AuthStateChangeCallback, Session, Subscription };\r\n\r\n/**\r\n * Main Genation SDK client\r\n *\r\n * OAuth 2.1 authentication client for Genation platform.\r\n * Supports PKCE flow and automatic token refresh.\r\n *\r\n * @example\r\n * ```typescript\r\n * import { createClient } from 'genation';\r\n *\r\n * const client = createClient({\r\n * clientId: 'your-client-id',\r\n * clientSecret: 'your-client-secret',\r\n * redirectUri: 'http://localhost:3000/callback'\r\n * });\r\n *\r\n * // Listen to auth state changes\r\n * const { subscription } = client.onAuthStateChange((event, session) => {\r\n * if (event === 'SIGNED_IN') {\r\n * console.log('User signed in:', session?.user);\r\n * }\r\n * });\r\n *\r\n * // Start login flow\r\n * window.location.href = await client.signIn();\r\n * ```\r\n */\r\nexport class GenationClient {\r\n private oauth: OAuth2Handler;\r\n private tokenManager: TokenManager;\r\n private http: HttpClient;\r\n private httpServer: HttpClient;\r\n private listeners: Set<AuthStateChangeCallback> = new Set();\r\n private initialized = false;\r\n\r\n constructor(config: GenationConfig) {\r\n this.validateConfig(config);\r\n\r\n const storage: TokenStorage = typeof config.storage === \"object\"\r\n ? (config.storage as unknown as TokenStorage)\r\n : createStorage(config.storage);\r\n\r\n this.tokenManager = new TokenManager(storage);\r\n this.oauth = new OAuth2Handler(config, this.tokenManager);\r\n this.http = new HttpClient({\r\n baseUrl: config.authUrl ??\r\n \"https://mnnoheowoowbtpuoguul.supabase.co/auth/v1\",\r\n });\r\n this.httpServer = new HttpClient({\r\n baseUrl: \"https://ff-api.genation.ai/api/v2/client\"\r\n });\r\n }\r\n\r\n private validateConfig(config: GenationConfig): void {\r\n if (!config.clientId) throw ConfigError.missingField(\"clientId\");\r\n if (!config.clientSecret) {\r\n throw ConfigError.missingField(\"clientSecret\");\r\n }\r\n if (!config.redirectUri) throw ConfigError.missingField(\"redirectUri\");\r\n }\r\n\r\n /**\r\n * Emit auth state change event to all listeners\r\n */\r\n private async emitAuthStateChange(event: AuthEvent): Promise<void> {\r\n const session = await this.getSession();\r\n this.listeners.forEach((callback) => {\r\n try {\r\n callback(event, session);\r\n } catch (error) {\r\n console.error(\"Error in auth state change callback:\", error);\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Listen to authentication state changes\r\n *\r\n * Register a callback that fires when:\r\n * - `INITIAL_SESSION`: On first subscription, with current session state\r\n * - `SIGNED_IN`: User successfully authenticated\r\n * - `SIGNED_OUT`: User logged out or session expired\r\n * - `TOKEN_REFRESHED`: Access token was automatically refreshed\r\n *\r\n * @param callback - Function called on each auth state change\r\n * @returns Object containing subscription with `unsubscribe()` method\r\n *\r\n * @example\r\n * ```typescript\r\n * const { subscription } = client.onAuthStateChange((event, session) => {\r\n * console.log('Auth event:', event);\r\n *\r\n * if (event === 'INITIAL_SESSION') {\r\n * // Check if user was previously logged in\r\n * if (session) {\r\n * console.log('Welcome back!', session.user);\r\n * }\r\n * } else if (event === 'SIGNED_IN') {\r\n * // User just signed in\r\n * console.log('Signed in:', session?.user);\r\n * } else if (event === 'SIGNED_OUT') {\r\n * // Clear app state, redirect to login\r\n * console.log('Signed out');\r\n * }\r\n * });\r\n *\r\n * // Cleanup when component unmounts\r\n * subscription.unsubscribe();\r\n * ```\r\n */\r\n onAuthStateChange(\r\n callback: AuthStateChangeCallback,\r\n ): { subscription: Subscription } {\r\n this.listeners.add(callback);\r\n\r\n // Emit INITIAL_SESSION on first subscription\r\n if (!this.initialized) {\r\n this.initialized = true;\r\n setTimeout(() => {\r\n this.emitAuthStateChange(\"INITIAL_SESSION\");\r\n }, 0);\r\n } else {\r\n // For subsequent subscriptions, also emit current state\r\n setTimeout(() => {\r\n this.emitAuthStateChange(\"INITIAL_SESSION\");\r\n }, 0);\r\n }\r\n\r\n return {\r\n subscription: {\r\n unsubscribe: () => {\r\n this.listeners.delete(callback);\r\n },\r\n },\r\n };\r\n }\r\n\r\n /**\r\n * Start OAuth sign-in flow\r\n *\r\n * Generates authorization URL with PKCE challenge.\r\n * Redirect user to this URL to start authentication.\r\n *\r\n * @returns Authorization URL to redirect user to\r\n *\r\n * @example\r\n * ```typescript\r\n * async function handleLogin() {\r\n * const url = await client.signIn();\r\n * window.location.href = url;\r\n * }\r\n * ```\r\n */\r\n async signIn(): Promise<string> {\r\n return this.oauth.getAuthorizationUrl();\r\n }\r\n\r\n /**\r\n * Handle OAuth callback after user authentication\r\n *\r\n * Call this on your redirect URI page to exchange\r\n * the authorization code for access tokens.\r\n * Triggers `SIGNED_IN` event on success.\r\n *\r\n * @param code - Authorization code from URL query params\r\n * @param state - State parameter for CSRF validation\r\n * @returns Token set with access and refresh tokens\r\n * @throws {AuthError} If state mismatch or code exchange fails\r\n *\r\n * @example\r\n * ```typescript\r\n * // On your /callback page\r\n * async function handleCallback() {\r\n * const url = window.location.href;\r\n * await client.handleCallback(url);\r\n * // onAuthStateChange will fire with SIGNED_IN event\r\n * }\r\n * ```\r\n */\r\n async handleCallback(url: string): Promise<TokenSet> {\r\n const params = new URLSearchParams(url);\r\n const code = params.get('code');\r\n const state = params.get('state');\r\n if (!code || !state) {\r\n throw new Error('Missing code or state');\r\n }\r\n const tokens = await this.oauth.exchangeCode(code, state);\r\n await this.emitAuthStateChange(\"SIGNED_IN\");\r\n return tokens;\r\n }\r\n\r\n // /**\r\n // * Sign out and revoke tokens\r\n // *\r\n // * Clears local session and revokes tokens on server.\r\n // * Triggers `SIGNED_OUT` event for all listeners.\r\n // *\r\n // * @example\r\n // * ```typescript\r\n // * async function handleLogout() {\r\n // * await client.signOut();\r\n // * // onAuthStateChange will fire with SIGNED_OUT event\r\n // * }\r\n // * ```\r\n // */\r\n // async signOut(): Promise<void> {\r\n // await this.oauth.revokeToken();\r\n // await this.emitAuthStateChange(\"SIGNED_OUT\");\r\n // }\r\n\r\n /**\r\n * Get current session\r\n *\r\n * Returns session with access token and user info.\r\n * Automatically refreshes token if expired.\r\n *\r\n * @returns Current session or null if not authenticated\r\n *\r\n * @example\r\n * ```typescript\r\n * const session = await client.getSession();\r\n * if (session) {\r\n * console.log('Logged in as:', session.user?.email);\r\n *\r\n * // Use access token for API calls\r\n * fetch('/api/data', {\r\n * headers: { Authorization: `Bearer ${session.accessToken}` }\r\n * });\r\n * }\r\n * ```\r\n */\r\n async getSession(): Promise<Session | null> {\r\n const isExpired = await this.tokenManager.isTokenExpired();\r\n\r\n if (isExpired) {\r\n try {\r\n await this.oauth.refreshToken();\r\n } catch {\r\n return null;\r\n }\r\n }\r\n\r\n const tokens = await this.tokenManager.getTokens();\r\n if (!tokens) return null;\r\n\r\n const user = await this.fetchUser(tokens.accessToken);\r\n\r\n return {\r\n accessToken: tokens.accessToken,\r\n refreshToken: tokens.refreshToken,\r\n expiresIn: tokens.expiresIn,\r\n expiresAt: tokens.issuedAt + tokens.expiresIn * 1000,\r\n user,\r\n };\r\n }\r\n /**\r\n * Get licenses\r\n * @param accessToken - The access token to use for the request\r\n * @param options - The options for the request\r\n * @param options.expiresAfter - Query licenses that are expired after the given date, default set to today to get all valid licenses (unexpired licenses)\r\n * @returns The licenses\r\n */\r\n async getLicenses(options: { expiresAfter?: Date } = {}): Promise<License[] | null> {\r\n const session = await this.getSession();\r\n if (!session) {\r\n return null;\r\n }\r\n const accessToken = session.accessToken;\r\n const { expiresAfter = new Date() } = options;\r\n const response = await this.httpServer.request<ApiResponse<LicenseResponse[]>>(\"/licenses\", {\r\n headers: { Authorization: `Bearer ${accessToken}` },\r\n params: { expiresAfter: expiresAfter.toISOString() }\r\n });\r\n if (!response.ok) {\r\n console.error(\"GenationClient: Error fetching licenses:\", response.error);\r\n return null;\r\n }\r\n const licenses: License[] = snakeToCamel(response.data);\r\n return licenses;\r\n }\r\n /**\r\n * Fetch user info from auth server\r\n */\r\n private async fetchUser(accessToken: string): Promise<User | null> {\r\n try {\r\n // Use standard OIDC UserInfo endpoint\r\n // https://supabase.com/docs/guides/auth/oauth-server/oauth-flows#userinfo-endpoint\r\n const response = await this.http.request<{\r\n sub: string;\r\n email?: string;\r\n name?: string;\r\n picture?: string;\r\n email_verified?: boolean;\r\n phone_number?: string;\r\n phone_number_verified?: boolean;\r\n }>(\"/oauth/userinfo\", {\r\n headers: { Authorization: `Bearer ${accessToken}` },\r\n });\r\n\r\n return {\r\n sub: response.sub,\r\n name: response.name,\r\n picture: response.picture,\r\n email: response.email,\r\n email_verified: response.email_verified,\r\n phone_number: response.phone_number,\r\n phone_number_verified: response.phone_number_verified,\r\n };\r\n } catch (error) {\r\n console.error(\"GenationClient: Error fetching user:\", error);\r\n return null;\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Create a new Genation client instance\r\n *\r\n * Factory function for creating SDK client with configuration.\r\n *\r\n * @param config - Client configuration options\r\n * @returns Configured GenationClient instance\r\n *\r\n * @example\r\n * ```typescript\r\n * import { createClient } from 'genation';\r\n *\r\n * const client = createClient({\r\n * clientId: 'your-client-id',\r\n * clientSecret: 'your-client-secret',\r\n * redirectUri: 'http://localhost:3000/callback',\r\n * // Optional\r\n * scopes: ['openid', 'profile', 'email'],\r\n * storage: 'localStorage',\r\n * });\r\n * ```\r\n */\r\nexport function createClient(config: GenationConfig): GenationClient {\r\n return new GenationClient(config);\r\n}\r\n"],"names":["GenationError","message","code","cause","AuthError","NetworkError","status","response","ConfigError","field","HttpClient","config","endpoint","options","method","headers","body","params","url","searchParams","controller","timeoutId","error","data","base64URLEncode","buffer","generateCodeVerifier","array","generateCodeChallenge","verifier","hash","generatePKCE","codeVerifier","codeChallenge","generateState","TOKEN_KEY","PKCE_KEY","STATE_KEY","TokenManager","storage","tokens","expiresAt","state","DEFAULT_AUTH_URL","OAuth2Handler","tokenManager","pkce","storedState","currentTokens","MemoryStorage","key","value","LocalStorage","prefix","k","SessionStorage","createStorage","type","snakeToCamel","_","c","GenationClient","event","session","callback","user","accessToken","expiresAfter","createClient"],"mappings":"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"}
@@ -1,13 +1,13 @@
1
1
  class m extends Error {
2
2
  code;
3
3
  cause;
4
- constructor(e, t, n) {
5
- super(e), this.name = "GenationError", this.code = t, this.cause = n;
4
+ constructor(e, t, s) {
5
+ super(e), this.name = "GenationError", this.code = t, this.cause = s;
6
6
  }
7
7
  }
8
8
  class l extends m {
9
- constructor(e, t, n) {
10
- super(e, t, n), this.name = "AuthError";
9
+ constructor(e, t, s) {
10
+ super(e, t, s), this.name = "AuthError";
11
11
  }
12
12
  static invalidGrant(e = "Invalid authorization code or refresh token") {
13
13
  return new l(e, "invalid_grant");
@@ -27,8 +27,8 @@ class l extends m {
27
27
  }
28
28
  class h extends m {
29
29
  status;
30
- constructor(e, t, n) {
31
- super(e, "network_error", n), this.name = "NetworkError", this.status = t;
30
+ constructor(e, t, s) {
31
+ super(e, "network_error", s), this.name = "NetworkError", this.status = t;
32
32
  }
33
33
  static fromResponse(e) {
34
34
  return new h(
@@ -55,19 +55,19 @@ class p {
55
55
  * Make an HTTP request
56
56
  */
57
57
  async request(e, t = {}) {
58
- const { method: n = "GET", headers: s = {}, body: i, params: a } = t;
59
- let c = `${this.baseUrl}${e}`;
60
- if (a) {
61
- const o = new URLSearchParams(a);
62
- c += `?${o.toString()}`;
58
+ const { method: s = "GET", headers: n = {}, body: i, params: c } = t;
59
+ let a = `${this.baseUrl}${e}`;
60
+ if (c) {
61
+ const o = new URLSearchParams(c);
62
+ a += `?${o.toString()}`;
63
63
  }
64
64
  const y = new AbortController(), S = setTimeout(() => y.abort(), this.timeout);
65
65
  try {
66
- const o = await fetch(c, {
67
- method: n,
66
+ const o = await fetch(a, {
67
+ method: s,
68
68
  headers: {
69
69
  "Content-Type": "application/json",
70
- ...s
70
+ ...n
71
71
  },
72
72
  body: i ? JSON.stringify(i) : void 0,
73
73
  signal: y.signal
@@ -82,51 +82,51 @@ class p {
82
82
  /**
83
83
  * POST request with form data (for OAuth token exchange)
84
84
  */
85
- async postForm(e, t, n = {}) {
86
- const s = `${this.baseUrl}${e}`, i = new AbortController(), a = setTimeout(() => i.abort(), this.timeout);
85
+ async postForm(e, t, s = {}) {
86
+ const n = `${this.baseUrl}${e}`, i = new AbortController(), c = setTimeout(() => i.abort(), this.timeout);
87
87
  try {
88
- const c = await fetch(s, {
88
+ const a = await fetch(n, {
89
89
  method: "POST",
90
90
  headers: {
91
91
  "Content-Type": "application/x-www-form-urlencoded",
92
- ...n
92
+ ...s
93
93
  },
94
94
  body: new URLSearchParams(t).toString(),
95
95
  signal: i.signal
96
96
  });
97
- if (clearTimeout(a), !c.ok)
98
- throw h.fromResponse(c);
99
- return await c.json();
100
- } catch (c) {
101
- throw clearTimeout(a), c instanceof h ? c : new h("Network request failed", void 0, c);
97
+ if (clearTimeout(c), !a.ok)
98
+ throw h.fromResponse(a);
99
+ return await a.json();
100
+ } catch (a) {
101
+ throw clearTimeout(c), a instanceof h ? a : new h("Network request failed", void 0, a);
102
102
  }
103
103
  }
104
104
  }
105
105
  function k(r) {
106
106
  return btoa(String.fromCharCode(...r)).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
107
107
  }
108
- function b() {
108
+ function _() {
109
109
  const r = new Uint8Array(32);
110
110
  return crypto.getRandomValues(r), k(r);
111
111
  }
112
- async function C(r) {
113
- const t = new TextEncoder().encode(r), n = await crypto.subtle.digest("SHA-256", t);
114
- return k(new Uint8Array(n));
112
+ async function b(r) {
113
+ const t = new TextEncoder().encode(r), s = await crypto.subtle.digest("SHA-256", t);
114
+ return k(new Uint8Array(s));
115
115
  }
116
- async function _() {
117
- const r = b(), e = await C(r);
116
+ async function v() {
117
+ const r = _(), e = await b(r);
118
118
  return {
119
119
  codeVerifier: r,
120
120
  codeChallenge: e,
121
121
  codeChallengeMethod: "S256"
122
122
  };
123
123
  }
124
- function v() {
124
+ function C() {
125
125
  const r = new Uint8Array(16);
126
126
  return crypto.getRandomValues(r), k(r);
127
127
  }
128
128
  const d = "tokens", g = "pkce", f = "state";
129
- class U {
129
+ class I {
130
130
  storage;
131
131
  constructor(e) {
132
132
  this.storage = e;
@@ -197,7 +197,7 @@ class U {
197
197
  await this.storage.clear();
198
198
  }
199
199
  }
200
- const I = "https://mnnoheowoowbtpuoguul.supabase.co/auth/v1";
200
+ const U = "https://mnnoheowoowbtpuoguul.supabase.co/auth/v1";
201
201
  class x {
202
202
  config;
203
203
  http;
@@ -208,7 +208,7 @@ class x {
208
208
  clientSecret: e.clientSecret,
209
209
  redirectUri: e.redirectUri,
210
210
  scopes: e.scopes,
211
- authUrl: e.authUrl ?? I
211
+ authUrl: e.authUrl ?? U
212
212
  }, this.http = new p({ baseUrl: this.config.authUrl }), this.tokenManager = t;
213
213
  }
214
214
  /**
@@ -216,9 +216,9 @@ class x {
216
216
  * Stores PKCE verifier and state for later validation
217
217
  */
218
218
  async getAuthorizationUrl() {
219
- const e = await _(), t = v();
219
+ const e = await v(), t = C();
220
220
  await this.tokenManager.setPKCE(e.codeVerifier), await this.tokenManager.setState(t);
221
- const n = new URLSearchParams({
221
+ const s = new URLSearchParams({
222
222
  response_type: "code",
223
223
  client_id: this.config.clientId,
224
224
  redirect_uri: this.config.redirectUri,
@@ -226,17 +226,17 @@ class x {
226
226
  code_challenge: e.codeChallenge,
227
227
  code_challenge_method: e.codeChallengeMethod
228
228
  });
229
- return this.config.scopes && this.config.scopes.length > 0 && n.append("scope", this.config.scopes.join(" ")), `${this.config.authUrl}/oauth/authorize?${n.toString()}`;
229
+ return this.config.scopes && this.config.scopes.length > 0 && s.append("scope", this.config.scopes.join(" ")), `${this.config.authUrl}/oauth/authorize?${s.toString()}`;
230
230
  }
231
231
  /**
232
232
  * Exchange authorization code for tokens
233
233
  */
234
234
  async exchangeCode(e, t) {
235
- const n = await this.tokenManager.consumeState();
236
- if (!n || n !== t)
235
+ const s = await this.tokenManager.consumeState();
236
+ if (!s || s !== t)
237
237
  throw l.invalidState();
238
- const s = await this.tokenManager.consumePKCE();
239
- if (!s)
238
+ const n = await this.tokenManager.consumePKCE();
239
+ if (!n)
240
240
  throw l.pkceVerificationFailed("Missing code verifier");
241
241
  const i = await this.http.postForm(
242
242
  "/oauth/token",
@@ -246,10 +246,10 @@ class x {
246
246
  redirect_uri: this.config.redirectUri,
247
247
  client_id: this.config.clientId,
248
248
  client_secret: this.config.clientSecret,
249
- code_verifier: s
249
+ code_verifier: n
250
250
  }
251
- ), a = this.mapTokenResponse(i);
252
- return await this.tokenManager.setTokens(a), a;
251
+ ), c = this.mapTokenResponse(i);
252
+ return await this.tokenManager.setTokens(c), c;
253
253
  }
254
254
  /**
255
255
  * Refresh access token using refresh token
@@ -266,8 +266,8 @@ class x {
266
266
  client_id: this.config.clientId,
267
267
  client_secret: this.config.clientSecret
268
268
  }
269
- ), n = this.mapTokenResponse(t);
270
- return await this.tokenManager.setTokens(n), n;
269
+ ), s = this.mapTokenResponse(t);
270
+ return await this.tokenManager.setTokens(s), s;
271
271
  }
272
272
  /**
273
273
  * Revoke current tokens
@@ -377,7 +377,7 @@ function M(r = "localStorage") {
377
377
  function w(r) {
378
378
  return Array.isArray(r) ? r.map(w) : typeof r == "object" && r !== null ? Object.fromEntries(
379
379
  Object.entries(r).map(([e, t]) => [
380
- e.replace(/_([a-z])/g, (n, s) => s.toUpperCase()),
380
+ e.replace(/_([a-z])/g, (s, n) => n.toUpperCase()),
381
381
  w(t)
382
382
  ])
383
383
  ) : r;
@@ -392,7 +392,7 @@ class K {
392
392
  constructor(e) {
393
393
  this.validateConfig(e);
394
394
  const t = typeof e.storage == "object" ? e.storage : M(e.storage);
395
- this.tokenManager = new U(t), this.oauth = new x(e, this.tokenManager), this.http = new p({
395
+ this.tokenManager = new I(t), this.oauth = new x(e, this.tokenManager), this.http = new p({
396
396
  baseUrl: e.authUrl ?? "https://mnnoheowoowbtpuoguul.supabase.co/auth/v1"
397
397
  }), this.httpServer = new p({
398
398
  baseUrl: "https://ff-api.genation.ai/api/v2/client"
@@ -409,11 +409,11 @@ class K {
409
409
  */
410
410
  async emitAuthStateChange(e) {
411
411
  const t = await this.getSession();
412
- this.listeners.forEach((n) => {
412
+ this.listeners.forEach((s) => {
413
413
  try {
414
- n(e, t);
415
- } catch (s) {
416
- console.error("Error in auth state change callback:", s);
414
+ s(e, t);
415
+ } catch (n) {
416
+ console.error("Error in auth state change callback:", n);
417
417
  }
418
418
  });
419
419
  }
@@ -500,26 +500,18 @@ class K {
500
500
  * ```typescript
501
501
  * // On your /callback page
502
502
  * async function handleCallback() {
503
- * const params = new URLSearchParams(window.location.search);
504
- * const code = params.get('code');
505
- * const state = params.get('state');
506
- *
507
- * if (code && state) {
508
- * await client.handleCallback(code, state);
509
- * // onAuthStateChange will fire with SIGNED_IN event
510
- * }
503
+ * const url = window.location.href;
504
+ * await client.handleCallback(url);
505
+ * // onAuthStateChange will fire with SIGNED_IN event
511
506
  * }
512
507
  * ```
513
508
  */
514
- async handleCallback(e, t) {
515
- const n = await this.oauth.exchangeCode(e, t);
516
- try {
517
- const s = await this.fetchUser(n.accessToken);
518
- console.log("Debug: handleCallback fetched user:", s);
519
- } catch (s) {
520
- console.error("Debug: handleCallback fetchUser failed:", s);
521
- }
522
- return await this.emitAuthStateChange("SIGNED_IN"), n;
509
+ async handleCallback(e) {
510
+ const t = new URLSearchParams(e), s = t.get("code"), n = t.get("state");
511
+ if (!s || !n)
512
+ throw new Error("Missing code or state");
513
+ const i = await this.oauth.exchangeCode(s, n);
514
+ return await this.emitAuthStateChange("SIGNED_IN"), i;
523
515
  }
524
516
  // /**
525
517
  // * Sign out and revoke tokens
@@ -569,13 +561,13 @@ class K {
569
561
  }
570
562
  const t = await this.tokenManager.getTokens();
571
563
  if (!t) return null;
572
- const n = await this.fetchUser(t.accessToken);
564
+ const s = await this.fetchUser(t.accessToken);
573
565
  return {
574
566
  accessToken: t.accessToken,
575
567
  refreshToken: t.refreshToken,
576
568
  expiresIn: t.expiresIn,
577
569
  expiresAt: t.issuedAt + t.expiresIn * 1e3,
578
- user: n
570
+ user: s
579
571
  };
580
572
  }
581
573
  /**
@@ -589,15 +581,11 @@ class K {
589
581
  const t = await this.getSession();
590
582
  if (!t)
591
583
  return null;
592
- const n = t.accessToken, { expiresAfter: s = /* @__PURE__ */ new Date() } = e, i = await this.httpServer.request("/licenses", {
593
- headers: { Authorization: `Bearer ${n}` },
594
- params: { expiresAfter: s.toISOString() }
584
+ const s = t.accessToken, { expiresAfter: n = /* @__PURE__ */ new Date() } = e, i = await this.httpServer.request("/licenses", {
585
+ headers: { Authorization: `Bearer ${s}` },
586
+ params: { expiresAfter: n.toISOString() }
595
587
  });
596
- if (!i.ok)
597
- return console.error("GenationClient: Error fetching licenses:", i.error), null;
598
- console.log("GenationClient: Response data:", i.data);
599
- const a = w(i.data);
600
- return console.log("GenationClient: Licenses:", a), a;
588
+ return i.ok ? w(i.data) : (console.error("GenationClient: Error fetching licenses:", i.error), null);
601
589
  }
602
590
  /**
603
591
  * Fetch user info from auth server
@@ -1 +1 @@
1
- {"version":3,"file":"genation.es.js","sources":["../src/http/errors.ts","../src/http/client.ts","../src/auth/pkce.ts","../src/auth/token-manager.ts","../src/auth/oauth.ts","../src/storage/memory.ts","../src/storage/local-storage.ts","../src/storage/session-storage.ts","../src/storage/index.ts","../src/utils/converter.ts","../src/client.ts"],"sourcesContent":["/**\r\n * Base error class for Genation SDK\r\n */\r\nexport class GenationError extends Error {\r\n public code: string;\r\n public cause?: unknown;\r\n\r\n constructor(message: string, code: string, cause?: unknown) {\r\n super(message);\r\n this.name = \"GenationError\";\r\n this.code = code;\r\n this.cause = cause;\r\n }\r\n}\r\n\r\n/**\r\n * Authentication-related errors\r\n */\r\nexport class AuthError extends GenationError {\r\n constructor(message: string, code: string, cause?: unknown) {\r\n super(message, code, cause);\r\n this.name = \"AuthError\";\r\n }\r\n\r\n static invalidGrant(\r\n message = \"Invalid authorization code or refresh token\",\r\n ) {\r\n return new AuthError(message, \"invalid_grant\");\r\n }\r\n\r\n static accessDenied(message = \"User denied access\") {\r\n return new AuthError(message, \"access_denied\");\r\n }\r\n\r\n static expiredToken(message = \"Token has expired\") {\r\n return new AuthError(message, \"expired_token\");\r\n }\r\n\r\n static invalidState(message = \"State mismatch, possible CSRF attack\") {\r\n return new AuthError(message, \"invalid_state\");\r\n }\r\n\r\n static pkceVerificationFailed(message = \"PKCE verification failed\") {\r\n return new AuthError(message, \"pkce_verification_failed\");\r\n }\r\n}\r\n\r\n/**\r\n * Network-related errors\r\n */\r\nexport class NetworkError extends GenationError {\r\n public status?: number;\r\n\r\n constructor(message: string, status?: number, cause?: unknown) {\r\n super(message, \"network_error\", cause);\r\n this.name = \"NetworkError\";\r\n this.status = status;\r\n }\r\n\r\n static fromResponse(response: Response) {\r\n return new NetworkError(\r\n `HTTP ${response.status}: ${response.statusText}`,\r\n response.status,\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Configuration-related errors\r\n */\r\nexport class ConfigError extends GenationError {\r\n constructor(message: string) {\r\n super(message, \"config_error\");\r\n this.name = \"ConfigError\";\r\n }\r\n\r\n static missingField(field: string) {\r\n return new ConfigError(`Missing required config field: ${field}`);\r\n }\r\n}\r\n","import { NetworkError } from \"./errors\";\r\n\r\nexport interface HttpClientConfig {\r\n baseUrl: string;\r\n timeout?: number;\r\n}\r\n\r\nexport interface RequestOptions {\r\n method?: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\";\r\n headers?: Record<string, string>;\r\n body?: unknown;\r\n params?: Record<string, string>;\r\n}\r\n\r\n/**\r\n * Simple HTTP client wrapper around fetch\r\n */\r\nexport class HttpClient {\r\n private baseUrl: string;\r\n private timeout: number;\r\n\r\n constructor(config: HttpClientConfig) {\r\n this.baseUrl = config.baseUrl.replace(/\\/$/, \"\");\r\n this.timeout = config.timeout ?? 30000;\r\n }\r\n\r\n /**\r\n * Make an HTTP request\r\n */\r\n async request<T>(\r\n endpoint: string,\r\n options: RequestOptions = {},\r\n ): Promise<T> {\r\n const { method = \"GET\", headers = {}, body, params } = options;\r\n\r\n // Build URL with query params\r\n let url = `${this.baseUrl}${endpoint}`;\r\n if (params) {\r\n const searchParams = new URLSearchParams(params);\r\n url += `?${searchParams.toString()}`;\r\n }\r\n\r\n // Setup abort controller for timeout\r\n const controller = new AbortController();\r\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\r\n\r\n try {\r\n const response = await fetch(url, {\r\n method,\r\n headers: {\r\n \"Content-Type\": \"application/json\",\r\n ...headers,\r\n },\r\n body: body ? JSON.stringify(body) : undefined,\r\n signal: controller.signal,\r\n });\r\n\r\n clearTimeout(timeoutId);\r\n\r\n if (!response.ok) {\r\n throw NetworkError.fromResponse(response);\r\n }\r\n\r\n return await response.json();\r\n } catch (error) {\r\n clearTimeout(timeoutId);\r\n\r\n if (error instanceof NetworkError) {\r\n throw error;\r\n }\r\n\r\n if (error instanceof Error && error.name === \"AbortError\") {\r\n throw new NetworkError(\"Request timeout\", undefined, error);\r\n }\r\n\r\n throw new NetworkError(\"Network request failed\", undefined, error);\r\n }\r\n }\r\n\r\n /**\r\n * POST request with form data (for OAuth token exchange)\r\n */\r\n async postForm<T>(\r\n endpoint: string,\r\n data: Record<string, string>,\r\n headers: Record<string, string> = {},\r\n ): Promise<T> {\r\n const url = `${this.baseUrl}${endpoint}`;\r\n const controller = new AbortController();\r\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\r\n\r\n try {\r\n const response = await fetch(url, {\r\n method: \"POST\",\r\n headers: {\r\n \"Content-Type\": \"application/x-www-form-urlencoded\",\r\n ...headers,\r\n },\r\n body: new URLSearchParams(data).toString(),\r\n signal: controller.signal,\r\n });\r\n\r\n clearTimeout(timeoutId);\r\n\r\n if (!response.ok) {\r\n throw NetworkError.fromResponse(response);\r\n }\r\n\r\n return await response.json();\r\n } catch (error) {\r\n clearTimeout(timeoutId);\r\n\r\n if (error instanceof NetworkError) {\r\n throw error;\r\n }\r\n\r\n throw new NetworkError(\"Network request failed\", undefined, error);\r\n }\r\n }\r\n}\r\n\r\nexport { AuthError, ConfigError, GenationError, NetworkError } from \"./errors\";\r\n","import type { PKCEChallenge } from \"../types\";\r\n\r\n/**\r\n * Base64URL encode a buffer (matches Supabase implementation)\r\n */\r\nfunction base64URLEncode(buffer: Uint8Array): string {\r\n return btoa(String.fromCharCode(...buffer))\r\n .replace(/\\+/g, \"-\")\r\n .replace(/\\//g, \"_\")\r\n .replace(/=/g, \"\");\r\n}\r\n\r\n/**\r\n * Generate a random code verifier (43-128 characters)\r\n * Matches Supabase implementation\r\n */\r\nfunction generateCodeVerifier(): string {\r\n const array = new Uint8Array(32);\r\n crypto.getRandomValues(array);\r\n return base64URLEncode(array);\r\n}\r\n\r\n/**\r\n * Create code challenge from verifier using SHA-256\r\n * Matches Supabase implementation\r\n */\r\nasync function generateCodeChallenge(verifier: string): Promise<string> {\r\n const encoder = new TextEncoder();\r\n const data = encoder.encode(verifier);\r\n const hash = await crypto.subtle.digest(\"SHA-256\", data);\r\n return base64URLEncode(new Uint8Array(hash));\r\n}\r\n\r\n/**\r\n * Generate PKCE code verifier and challenge pair\r\n * Uses S256 method as required by OAuth 2.1\r\n */\r\nexport async function generatePKCE(): Promise<PKCEChallenge> {\r\n const codeVerifier = generateCodeVerifier();\r\n const codeChallenge = await generateCodeChallenge(codeVerifier);\r\n\r\n return {\r\n codeVerifier,\r\n codeChallenge,\r\n codeChallengeMethod: \"S256\",\r\n };\r\n}\r\n\r\n/**\r\n * Generate random state parameter for CSRF protection\r\n */\r\nexport function generateState(): string {\r\n const array = new Uint8Array(16);\r\n crypto.getRandomValues(array);\r\n return base64URLEncode(array);\r\n}\r\n","import type { TokenSet, TokenStorage } from \"../types\";\r\n\r\nconst TOKEN_KEY = \"tokens\";\r\nconst PKCE_KEY = \"pkce\";\r\nconst STATE_KEY = \"state\";\r\n\r\n/**\r\n * Manages token lifecycle: storage, retrieval, refresh\r\n */\r\nexport class TokenManager {\r\n private storage: TokenStorage;\r\n\r\n constructor(storage: TokenStorage) {\r\n this.storage = storage;\r\n }\r\n\r\n /**\r\n * Store token set\r\n */\r\n async setTokens(tokens: TokenSet): Promise<void> {\r\n await this.storage.set(TOKEN_KEY, JSON.stringify(tokens));\r\n }\r\n\r\n /**\r\n * Get stored tokens\r\n */\r\n async getTokens(): Promise<TokenSet | null> {\r\n const data = await this.storage.get(TOKEN_KEY);\r\n if (!data) return null;\r\n\r\n try {\r\n return JSON.parse(data) as TokenSet;\r\n } catch {\r\n return null;\r\n }\r\n }\r\n\r\n /**\r\n * Clear stored tokens\r\n */\r\n async clearTokens(): Promise<void> {\r\n await this.storage.remove(TOKEN_KEY);\r\n }\r\n\r\n /**\r\n * Check if access token is expired\r\n */\r\n async isTokenExpired(): Promise<boolean> {\r\n const tokens = await this.getTokens();\r\n if (!tokens) return true;\r\n\r\n const expiresAt = tokens.issuedAt + tokens.expiresIn * 1000;\r\n // Consider expired if less than 60 seconds remaining\r\n return Date.now() > expiresAt - 60000;\r\n }\r\n\r\n /**\r\n * Store PKCE verifier for later validation\r\n */\r\n async setPKCE(codeVerifier: string): Promise<void> {\r\n await this.storage.set(PKCE_KEY, codeVerifier);\r\n }\r\n\r\n /**\r\n * Get and clear stored PKCE verifier\r\n */\r\n async consumePKCE(): Promise<string | null> {\r\n const verifier = await this.storage.get(PKCE_KEY);\r\n if (verifier) {\r\n await this.storage.remove(PKCE_KEY);\r\n }\r\n return verifier;\r\n }\r\n\r\n /**\r\n * Store state for CSRF validation\r\n */\r\n async setState(state: string): Promise<void> {\r\n await this.storage.set(STATE_KEY, state);\r\n }\r\n\r\n /**\r\n * Get and clear stored state\r\n */\r\n async consumeState(): Promise<string | null> {\r\n const state = await this.storage.get(STATE_KEY);\r\n if (state) {\r\n await this.storage.remove(STATE_KEY);\r\n }\r\n return state;\r\n }\r\n\r\n /**\r\n * Clear all auth-related data\r\n */\r\n async clearAll(): Promise<void> {\r\n await this.storage.clear();\r\n }\r\n}\r\n","import type { GenationConfig, TokenSet } from \"../types\";\r\nimport { AuthError, HttpClient } from \"../http\";\r\nimport { generatePKCE, generateState } from \"./pkce\";\r\nimport { TokenManager } from \"./token-manager\";\r\n\r\nconst DEFAULT_AUTH_URL = \"https://mnnoheowoowbtpuoguul.supabase.co/auth/v1\";\r\n\r\ninterface TokenResponse {\r\n access_token: string;\r\n refresh_token?: string;\r\n token_type: string;\r\n expires_in: number;\r\n scope?: string;\r\n}\r\n\r\n/**\r\n * OAuth 2.1 handler with PKCE support\r\n */\r\nexport class OAuth2Handler {\r\n private config:\r\n & Required<\r\n Pick<GenationConfig, \"clientId\" | \"clientSecret\" | \"redirectUri\">\r\n >\r\n & Pick<GenationConfig, \"scopes\" | \"authUrl\">;\r\n private http: HttpClient;\r\n private tokenManager: TokenManager;\r\n\r\n constructor(\r\n config: GenationConfig,\r\n tokenManager: TokenManager,\r\n ) {\r\n this.config = {\r\n clientId: config.clientId,\r\n clientSecret: config.clientSecret,\r\n redirectUri: config.redirectUri,\r\n scopes: config.scopes,\r\n authUrl: config.authUrl ?? DEFAULT_AUTH_URL,\r\n };\r\n this.http = new HttpClient({ baseUrl: this.config.authUrl! });\r\n this.tokenManager = tokenManager;\r\n }\r\n\r\n /**\r\n * Generate authorization URL for OAuth flow\r\n * Stores PKCE verifier and state for later validation\r\n */\r\n async getAuthorizationUrl(): Promise<string> {\r\n const pkce = await generatePKCE();\r\n const state = generateState();\r\n\r\n // Store for later validation\r\n await this.tokenManager.setPKCE(pkce.codeVerifier);\r\n await this.tokenManager.setState(state);\r\n\r\n const params = new URLSearchParams({\r\n response_type: \"code\",\r\n client_id: this.config.clientId,\r\n redirect_uri: this.config.redirectUri,\r\n state,\r\n code_challenge: pkce.codeChallenge,\r\n code_challenge_method: pkce.codeChallengeMethod,\r\n });\r\n\r\n if (this.config.scopes && this.config.scopes.length > 0) {\r\n params.append(\"scope\", this.config.scopes.join(\" \"));\r\n }\r\n\r\n return `${this.config.authUrl}/oauth/authorize?${params.toString()}`;\r\n }\r\n\r\n /**\r\n * Exchange authorization code for tokens\r\n */\r\n async exchangeCode(code: string, state: string): Promise<TokenSet> {\r\n // Validate state\r\n const storedState = await this.tokenManager.consumeState();\r\n if (!storedState || storedState !== state) {\r\n throw AuthError.invalidState();\r\n }\r\n\r\n // Get PKCE verifier\r\n const codeVerifier = await this.tokenManager.consumePKCE();\r\n if (!codeVerifier) {\r\n throw AuthError.pkceVerificationFailed(\"Missing code verifier\");\r\n }\r\n\r\n // Exchange code for tokens\r\n const response = await this.http.postForm<TokenResponse>(\r\n \"/oauth/token\",\r\n {\r\n grant_type: \"authorization_code\",\r\n code,\r\n redirect_uri: this.config.redirectUri,\r\n client_id: this.config.clientId,\r\n client_secret: this.config.clientSecret,\r\n code_verifier: codeVerifier,\r\n },\r\n );\r\n\r\n const tokens = this.mapTokenResponse(response);\r\n await this.tokenManager.setTokens(tokens);\r\n\r\n return tokens;\r\n }\r\n\r\n /**\r\n * Refresh access token using refresh token\r\n */\r\n async refreshToken(): Promise<TokenSet> {\r\n const currentTokens = await this.tokenManager.getTokens();\r\n if (!currentTokens?.refreshToken) {\r\n throw AuthError.invalidGrant(\"No refresh token available\");\r\n }\r\n\r\n const response = await this.http.postForm<TokenResponse>(\r\n \"/oauth/token\",\r\n {\r\n grant_type: \"refresh_token\",\r\n refresh_token: currentTokens.refreshToken,\r\n client_id: this.config.clientId,\r\n client_secret: this.config.clientSecret,\r\n },\r\n );\r\n\r\n const tokens = this.mapTokenResponse(response);\r\n await this.tokenManager.setTokens(tokens);\r\n\r\n return tokens;\r\n }\r\n\r\n /**\r\n * Revoke current tokens\r\n */\r\n async revokeToken(): Promise<void> {\r\n const tokens = await this.tokenManager.getTokens();\r\n if (!tokens) return;\r\n\r\n try {\r\n await this.http.postForm(\"/oauth/revoke\", {\r\n token: tokens.accessToken,\r\n client_id: this.config.clientId,\r\n client_secret: this.config.clientSecret,\r\n });\r\n } finally {\r\n await this.tokenManager.clearTokens();\r\n }\r\n }\r\n\r\n /**\r\n * Map OAuth token response to TokenSet\r\n */\r\n private mapTokenResponse(response: TokenResponse): TokenSet {\r\n return {\r\n accessToken: response.access_token,\r\n refreshToken: response.refresh_token,\r\n tokenType: response.token_type,\r\n expiresIn: response.expires_in,\r\n issuedAt: Date.now(),\r\n scope: response.scope,\r\n };\r\n }\r\n}\r\n","import type { TokenStorage } from \"../types\";\r\n\r\n/**\r\n * In-memory storage implementation\r\n * Tokens are lost when page refreshes\r\n */\r\nexport class MemoryStorage implements TokenStorage {\r\n private store = new Map<string, string>();\r\n\r\n async get(key: string): Promise<string | null> {\r\n return this.store.get(key) ?? null;\r\n }\r\n\r\n async set(key: string, value: string): Promise<void> {\r\n this.store.set(key, value);\r\n }\r\n\r\n async remove(key: string): Promise<void> {\r\n this.store.delete(key);\r\n }\r\n\r\n async clear(): Promise<void> {\r\n this.store.clear();\r\n }\r\n}\r\n","import type { TokenStorage } from \"../types\";\r\n\r\n/**\r\n * Browser localStorage implementation\r\n * Tokens persist across browser sessions\r\n */\r\nexport class LocalStorage implements TokenStorage {\r\n private prefix: string;\r\n\r\n constructor(prefix = \"genation\") {\r\n this.prefix = prefix;\r\n }\r\n\r\n private getKey(key: string): string {\r\n return `${this.prefix}:${key}`;\r\n }\r\n\r\n async get(key: string): Promise<string | null> {\r\n if (typeof window === \"undefined\") return null;\r\n return localStorage.getItem(this.getKey(key));\r\n }\r\n\r\n async set(key: string, value: string): Promise<void> {\r\n if (typeof window === \"undefined\") return;\r\n localStorage.setItem(this.getKey(key), value);\r\n }\r\n\r\n async remove(key: string): Promise<void> {\r\n if (typeof window === \"undefined\") return;\r\n localStorage.removeItem(this.getKey(key));\r\n }\r\n\r\n async clear(): Promise<void> {\r\n if (typeof window === \"undefined\") return;\r\n const keys = Object.keys(localStorage).filter((k) =>\r\n k.startsWith(`${this.prefix}:`)\r\n );\r\n keys.forEach((k) => localStorage.removeItem(k));\r\n }\r\n}\r\n","import type { TokenStorage } from \"../types\";\r\n\r\n/**\r\n * Browser sessionStorage implementation\r\n * Tokens persist until browser tab is closed\r\n */\r\nexport class SessionStorage implements TokenStorage {\r\n private prefix: string;\r\n\r\n constructor(prefix = \"genation\") {\r\n this.prefix = prefix;\r\n }\r\n\r\n private getKey(key: string): string {\r\n return `${this.prefix}:${key}`;\r\n }\r\n\r\n async get(key: string): Promise<string | null> {\r\n if (typeof window === \"undefined\") return null;\r\n return sessionStorage.getItem(this.getKey(key));\r\n }\r\n\r\n async set(key: string, value: string): Promise<void> {\r\n if (typeof window === \"undefined\") return;\r\n sessionStorage.setItem(this.getKey(key), value);\r\n }\r\n\r\n async remove(key: string): Promise<void> {\r\n if (typeof window === \"undefined\") return;\r\n sessionStorage.removeItem(this.getKey(key));\r\n }\r\n\r\n async clear(): Promise<void> {\r\n if (typeof window === \"undefined\") return;\r\n const keys = Object.keys(sessionStorage).filter((k) =>\r\n k.startsWith(`${this.prefix}:`)\r\n );\r\n keys.forEach((k) => sessionStorage.removeItem(k));\r\n }\r\n}\r\n","/**\r\n * @fileoverview Storage factory and implementations\r\n * @module storage\r\n */\r\n\r\nimport type { StorageType, TokenStorage } from \"../types\";\r\nimport { MemoryStorage } from \"./memory\";\r\nimport { LocalStorage } from \"./local-storage\";\r\nimport { SessionStorage } from \"./session-storage\";\r\n\r\nexport { MemoryStorage } from \"./memory\";\r\nexport { LocalStorage } from \"./local-storage\";\r\nexport { SessionStorage } from \"./session-storage\";\r\n\r\n/**\r\n * Create a storage instance based on type\r\n *\r\n * @param type - Storage type to create\r\n * @returns Storage implementation\r\n *\r\n * @example\r\n * ```typescript\r\n * const storage = createStorage('localStorage');\r\n * await storage.set('key', 'value');\r\n * ```\r\n */\r\nexport function createStorage(\r\n type: StorageType = \"localStorage\",\r\n): TokenStorage {\r\n switch (type) {\r\n case \"memory\":\r\n return new MemoryStorage();\r\n case \"localStorage\":\r\n return new LocalStorage();\r\n case \"sessionStorage\":\r\n return new SessionStorage();\r\n default:\r\n return new LocalStorage();\r\n }\r\n}\r\n","// Function to convert snake_case to camelCase, handles arrays and objects recursively\r\nexport function snakeToCamel(data: any): any {\r\n if (Array.isArray(data)) {\r\n return data.map(snakeToCamel);\r\n } else if (typeof data === \"object\" && data !== null) {\r\n return Object.fromEntries(\r\n Object.entries(data).map(([key, value]) => [\r\n key.replace(/_([a-z])/g, (_, c) => c.toUpperCase()),\r\n snakeToCamel(value)\r\n ])\r\n );\r\n }\r\n return data;\r\n}","/**\r\n * @fileoverview Main Genation SDK client\r\n * @module client\r\n */\r\n\r\nimport type {\r\n AuthEvent,\r\n AuthStateChangeCallback,\r\n GenationConfig,\r\n Session,\r\n Subscription,\r\n TokenSet,\r\n TokenStorage,\r\n User,\r\n} from \"./types\";\r\nimport { OAuth2Handler, TokenManager } from \"./auth\";\r\nimport { createStorage } from \"./storage\";\r\nimport { ConfigError, HttpClient } from \"./http\";\r\nimport type { License, LicenseResponse } from \"./types/server/license\";\r\nimport type { ApiResponse } from \"./types/server/api-response\";\r\nimport { snakeToCamel } from \"./utils/converter\";\r\n\r\n// Re-export types for convenience\r\nexport type { AuthEvent, AuthStateChangeCallback, Session, Subscription };\r\n\r\n/**\r\n * Main Genation SDK client\r\n *\r\n * OAuth 2.1 authentication client for Genation platform.\r\n * Supports PKCE flow and automatic token refresh.\r\n *\r\n * @example\r\n * ```typescript\r\n * import { createClient } from 'genation';\r\n *\r\n * const client = createClient({\r\n * clientId: 'your-client-id',\r\n * clientSecret: 'your-client-secret',\r\n * redirectUri: 'http://localhost:3000/callback'\r\n * });\r\n *\r\n * // Listen to auth state changes\r\n * const { subscription } = client.onAuthStateChange((event, session) => {\r\n * if (event === 'SIGNED_IN') {\r\n * console.log('User signed in:', session?.user);\r\n * }\r\n * });\r\n *\r\n * // Start login flow\r\n * window.location.href = await client.signIn();\r\n * ```\r\n */\r\nexport class GenationClient {\r\n private oauth: OAuth2Handler;\r\n private tokenManager: TokenManager;\r\n private http: HttpClient;\r\n private httpServer: HttpClient;\r\n private listeners: Set<AuthStateChangeCallback> = new Set();\r\n private initialized = false;\r\n\r\n constructor(config: GenationConfig) {\r\n this.validateConfig(config);\r\n\r\n const storage: TokenStorage = typeof config.storage === \"object\"\r\n ? (config.storage as unknown as TokenStorage)\r\n : createStorage(config.storage);\r\n\r\n this.tokenManager = new TokenManager(storage);\r\n this.oauth = new OAuth2Handler(config, this.tokenManager);\r\n this.http = new HttpClient({\r\n baseUrl: config.authUrl ??\r\n \"https://mnnoheowoowbtpuoguul.supabase.co/auth/v1\",\r\n });\r\n this.httpServer = new HttpClient({\r\n baseUrl: \"https://ff-api.genation.ai/api/v2/client\"\r\n });\r\n }\r\n\r\n private validateConfig(config: GenationConfig): void {\r\n if (!config.clientId) throw ConfigError.missingField(\"clientId\");\r\n if (!config.clientSecret) {\r\n throw ConfigError.missingField(\"clientSecret\");\r\n }\r\n if (!config.redirectUri) throw ConfigError.missingField(\"redirectUri\");\r\n }\r\n\r\n /**\r\n * Emit auth state change event to all listeners\r\n */\r\n private async emitAuthStateChange(event: AuthEvent): Promise<void> {\r\n const session = await this.getSession();\r\n this.listeners.forEach((callback) => {\r\n try {\r\n callback(event, session);\r\n } catch (error) {\r\n console.error(\"Error in auth state change callback:\", error);\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Listen to authentication state changes\r\n *\r\n * Register a callback that fires when:\r\n * - `INITIAL_SESSION`: On first subscription, with current session state\r\n * - `SIGNED_IN`: User successfully authenticated\r\n * - `SIGNED_OUT`: User logged out or session expired\r\n * - `TOKEN_REFRESHED`: Access token was automatically refreshed\r\n *\r\n * @param callback - Function called on each auth state change\r\n * @returns Object containing subscription with `unsubscribe()` method\r\n *\r\n * @example\r\n * ```typescript\r\n * const { subscription } = client.onAuthStateChange((event, session) => {\r\n * console.log('Auth event:', event);\r\n *\r\n * if (event === 'INITIAL_SESSION') {\r\n * // Check if user was previously logged in\r\n * if (session) {\r\n * console.log('Welcome back!', session.user);\r\n * }\r\n * } else if (event === 'SIGNED_IN') {\r\n * // User just signed in\r\n * console.log('Signed in:', session?.user);\r\n * } else if (event === 'SIGNED_OUT') {\r\n * // Clear app state, redirect to login\r\n * console.log('Signed out');\r\n * }\r\n * });\r\n *\r\n * // Cleanup when component unmounts\r\n * subscription.unsubscribe();\r\n * ```\r\n */\r\n onAuthStateChange(\r\n callback: AuthStateChangeCallback,\r\n ): { subscription: Subscription } {\r\n this.listeners.add(callback);\r\n\r\n // Emit INITIAL_SESSION on first subscription\r\n if (!this.initialized) {\r\n this.initialized = true;\r\n setTimeout(() => {\r\n this.emitAuthStateChange(\"INITIAL_SESSION\");\r\n }, 0);\r\n } else {\r\n // For subsequent subscriptions, also emit current state\r\n setTimeout(() => {\r\n this.emitAuthStateChange(\"INITIAL_SESSION\");\r\n }, 0);\r\n }\r\n\r\n return {\r\n subscription: {\r\n unsubscribe: () => {\r\n this.listeners.delete(callback);\r\n },\r\n },\r\n };\r\n }\r\n\r\n /**\r\n * Start OAuth sign-in flow\r\n *\r\n * Generates authorization URL with PKCE challenge.\r\n * Redirect user to this URL to start authentication.\r\n *\r\n * @returns Authorization URL to redirect user to\r\n *\r\n * @example\r\n * ```typescript\r\n * async function handleLogin() {\r\n * const url = await client.signIn();\r\n * window.location.href = url;\r\n * }\r\n * ```\r\n */\r\n async signIn(): Promise<string> {\r\n return this.oauth.getAuthorizationUrl();\r\n }\r\n\r\n /**\r\n * Handle OAuth callback after user authentication\r\n *\r\n * Call this on your redirect URI page to exchange\r\n * the authorization code for access tokens.\r\n * Triggers `SIGNED_IN` event on success.\r\n *\r\n * @param code - Authorization code from URL query params\r\n * @param state - State parameter for CSRF validation\r\n * @returns Token set with access and refresh tokens\r\n * @throws {AuthError} If state mismatch or code exchange fails\r\n *\r\n * @example\r\n * ```typescript\r\n * // On your /callback page\r\n * async function handleCallback() {\r\n * const params = new URLSearchParams(window.location.search);\r\n * const code = params.get('code');\r\n * const state = params.get('state');\r\n *\r\n * if (code && state) {\r\n * await client.handleCallback(code, state);\r\n * // onAuthStateChange will fire with SIGNED_IN event\r\n * }\r\n * }\r\n * ```\r\n */\r\n async handleCallback(code: string, state: string): Promise<TokenSet> {\r\n const tokens = await this.oauth.exchangeCode(code, state);\r\n\r\n // Debug: Fetch user immediately to check if it works\r\n try {\r\n const user = await this.fetchUser(tokens.accessToken);\r\n console.log(\"Debug: handleCallback fetched user:\", user);\r\n } catch (e) {\r\n console.error(\"Debug: handleCallback fetchUser failed:\", e);\r\n }\r\n\r\n await this.emitAuthStateChange(\"SIGNED_IN\");\r\n return tokens;\r\n }\r\n\r\n // /**\r\n // * Sign out and revoke tokens\r\n // *\r\n // * Clears local session and revokes tokens on server.\r\n // * Triggers `SIGNED_OUT` event for all listeners.\r\n // *\r\n // * @example\r\n // * ```typescript\r\n // * async function handleLogout() {\r\n // * await client.signOut();\r\n // * // onAuthStateChange will fire with SIGNED_OUT event\r\n // * }\r\n // * ```\r\n // */\r\n // async signOut(): Promise<void> {\r\n // await this.oauth.revokeToken();\r\n // await this.emitAuthStateChange(\"SIGNED_OUT\");\r\n // }\r\n\r\n /**\r\n * Get current session\r\n *\r\n * Returns session with access token and user info.\r\n * Automatically refreshes token if expired.\r\n *\r\n * @returns Current session or null if not authenticated\r\n *\r\n * @example\r\n * ```typescript\r\n * const session = await client.getSession();\r\n * if (session) {\r\n * console.log('Logged in as:', session.user?.email);\r\n *\r\n * // Use access token for API calls\r\n * fetch('/api/data', {\r\n * headers: { Authorization: `Bearer ${session.accessToken}` }\r\n * });\r\n * }\r\n * ```\r\n */\r\n async getSession(): Promise<Session | null> {\r\n const isExpired = await this.tokenManager.isTokenExpired();\r\n\r\n if (isExpired) {\r\n try {\r\n await this.oauth.refreshToken();\r\n } catch {\r\n return null;\r\n }\r\n }\r\n\r\n const tokens = await this.tokenManager.getTokens();\r\n if (!tokens) return null;\r\n\r\n const user = await this.fetchUser(tokens.accessToken);\r\n\r\n return {\r\n accessToken: tokens.accessToken,\r\n refreshToken: tokens.refreshToken,\r\n expiresIn: tokens.expiresIn,\r\n expiresAt: tokens.issuedAt + tokens.expiresIn * 1000,\r\n user,\r\n };\r\n }\r\n /**\r\n * Get licenses\r\n * @param accessToken - The access token to use for the request\r\n * @param options - The options for the request\r\n * @param options.expiresAfter - Query licenses that are expired after the given date, default set to today to get all valid licenses (unexpired licenses)\r\n * @returns The licenses\r\n */\r\n async getLicenses(options: { expiresAfter?: Date } = {}): Promise<License[] | null> {\r\n const session = await this.getSession();\r\n if (!session) {\r\n return null;\r\n }\r\n const accessToken = session.accessToken;\r\n const { expiresAfter = new Date() } = options;\r\n const response = await this.httpServer.request<ApiResponse<LicenseResponse[]>>(\"/licenses\", {\r\n headers: { Authorization: `Bearer ${accessToken}` },\r\n params: { expiresAfter: expiresAfter.toISOString() }\r\n });\r\n if (!response.ok) {\r\n console.error(\"GenationClient: Error fetching licenses:\", response.error);\r\n return null;\r\n }\r\n console.log(\"GenationClient: Response data:\", response.data);\r\n const licenses: License[] = snakeToCamel(response.data);\r\n console.log(\"GenationClient: Licenses:\", licenses);\r\n return licenses;\r\n }\r\n /**\r\n * Fetch user info from auth server\r\n */\r\n private async fetchUser(accessToken: string): Promise<User | null> {\r\n try {\r\n // Use standard OIDC UserInfo endpoint\r\n // https://supabase.com/docs/guides/auth/oauth-server/oauth-flows#userinfo-endpoint\r\n const response = await this.http.request<{\r\n sub: string;\r\n email?: string;\r\n name?: string;\r\n picture?: string;\r\n email_verified?: boolean;\r\n phone_number?: string;\r\n phone_number_verified?: boolean;\r\n }>(\"/oauth/userinfo\", {\r\n headers: { Authorization: `Bearer ${accessToken}` },\r\n });\r\n\r\n return {\r\n sub: response.sub,\r\n name: response.name,\r\n picture: response.picture,\r\n email: response.email,\r\n email_verified: response.email_verified,\r\n phone_number: response.phone_number,\r\n phone_number_verified: response.phone_number_verified,\r\n };\r\n } catch (error) {\r\n console.error(\"GenationClient: Error fetching user:\", error);\r\n return null;\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Create a new Genation client instance\r\n *\r\n * Factory function for creating SDK client with configuration.\r\n *\r\n * @param config - Client configuration options\r\n * @returns Configured GenationClient instance\r\n *\r\n * @example\r\n * ```typescript\r\n * import { createClient } from 'genation';\r\n *\r\n * const client = createClient({\r\n * clientId: 'your-client-id',\r\n * clientSecret: 'your-client-secret',\r\n * redirectUri: 'http://localhost:3000/callback',\r\n * // Optional\r\n * scopes: ['openid', 'profile', 'email'],\r\n * storage: 'localStorage',\r\n * });\r\n * ```\r\n */\r\nexport function createClient(config: GenationConfig): GenationClient {\r\n return new GenationClient(config);\r\n}\r\n"],"names":["GenationError","message","code","cause","AuthError","NetworkError","status","response","ConfigError","field","HttpClient","config","endpoint","options","method","headers","body","params","url","searchParams","controller","timeoutId","error","data","base64URLEncode","buffer","generateCodeVerifier","array","generateCodeChallenge","verifier","hash","generatePKCE","codeVerifier","codeChallenge","generateState","TOKEN_KEY","PKCE_KEY","STATE_KEY","TokenManager","storage","tokens","expiresAt","state","DEFAULT_AUTH_URL","OAuth2Handler","tokenManager","pkce","storedState","currentTokens","MemoryStorage","key","value","LocalStorage","prefix","k","SessionStorage","createStorage","type","snakeToCamel","_","c","GenationClient","event","session","callback","user","e","accessToken","expiresAfter","licenses","createClient"],"mappings":"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"}
1
+ {"version":3,"file":"genation.es.js","sources":["../src/http/errors.ts","../src/http/client.ts","../src/auth/pkce.ts","../src/auth/token-manager.ts","../src/auth/oauth.ts","../src/storage/memory.ts","../src/storage/local-storage.ts","../src/storage/session-storage.ts","../src/storage/index.ts","../src/utils/converter.ts","../src/client.ts"],"sourcesContent":["/**\r\n * Base error class for Genation SDK\r\n */\r\nexport class GenationError extends Error {\r\n public code: string;\r\n public cause?: unknown;\r\n\r\n constructor(message: string, code: string, cause?: unknown) {\r\n super(message);\r\n this.name = \"GenationError\";\r\n this.code = code;\r\n this.cause = cause;\r\n }\r\n}\r\n\r\n/**\r\n * Authentication-related errors\r\n */\r\nexport class AuthError extends GenationError {\r\n constructor(message: string, code: string, cause?: unknown) {\r\n super(message, code, cause);\r\n this.name = \"AuthError\";\r\n }\r\n\r\n static invalidGrant(\r\n message = \"Invalid authorization code or refresh token\",\r\n ) {\r\n return new AuthError(message, \"invalid_grant\");\r\n }\r\n\r\n static accessDenied(message = \"User denied access\") {\r\n return new AuthError(message, \"access_denied\");\r\n }\r\n\r\n static expiredToken(message = \"Token has expired\") {\r\n return new AuthError(message, \"expired_token\");\r\n }\r\n\r\n static invalidState(message = \"State mismatch, possible CSRF attack\") {\r\n return new AuthError(message, \"invalid_state\");\r\n }\r\n\r\n static pkceVerificationFailed(message = \"PKCE verification failed\") {\r\n return new AuthError(message, \"pkce_verification_failed\");\r\n }\r\n}\r\n\r\n/**\r\n * Network-related errors\r\n */\r\nexport class NetworkError extends GenationError {\r\n public status?: number;\r\n\r\n constructor(message: string, status?: number, cause?: unknown) {\r\n super(message, \"network_error\", cause);\r\n this.name = \"NetworkError\";\r\n this.status = status;\r\n }\r\n\r\n static fromResponse(response: Response) {\r\n return new NetworkError(\r\n `HTTP ${response.status}: ${response.statusText}`,\r\n response.status,\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Configuration-related errors\r\n */\r\nexport class ConfigError extends GenationError {\r\n constructor(message: string) {\r\n super(message, \"config_error\");\r\n this.name = \"ConfigError\";\r\n }\r\n\r\n static missingField(field: string) {\r\n return new ConfigError(`Missing required config field: ${field}`);\r\n }\r\n}\r\n","import { NetworkError } from \"./errors\";\r\n\r\nexport interface HttpClientConfig {\r\n baseUrl: string;\r\n timeout?: number;\r\n}\r\n\r\nexport interface RequestOptions {\r\n method?: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\";\r\n headers?: Record<string, string>;\r\n body?: unknown;\r\n params?: Record<string, string>;\r\n}\r\n\r\n/**\r\n * Simple HTTP client wrapper around fetch\r\n */\r\nexport class HttpClient {\r\n private baseUrl: string;\r\n private timeout: number;\r\n\r\n constructor(config: HttpClientConfig) {\r\n this.baseUrl = config.baseUrl.replace(/\\/$/, \"\");\r\n this.timeout = config.timeout ?? 30000;\r\n }\r\n\r\n /**\r\n * Make an HTTP request\r\n */\r\n async request<T>(\r\n endpoint: string,\r\n options: RequestOptions = {},\r\n ): Promise<T> {\r\n const { method = \"GET\", headers = {}, body, params } = options;\r\n\r\n // Build URL with query params\r\n let url = `${this.baseUrl}${endpoint}`;\r\n if (params) {\r\n const searchParams = new URLSearchParams(params);\r\n url += `?${searchParams.toString()}`;\r\n }\r\n\r\n // Setup abort controller for timeout\r\n const controller = new AbortController();\r\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\r\n\r\n try {\r\n const response = await fetch(url, {\r\n method,\r\n headers: {\r\n \"Content-Type\": \"application/json\",\r\n ...headers,\r\n },\r\n body: body ? JSON.stringify(body) : undefined,\r\n signal: controller.signal,\r\n });\r\n\r\n clearTimeout(timeoutId);\r\n\r\n if (!response.ok) {\r\n throw NetworkError.fromResponse(response);\r\n }\r\n\r\n return await response.json();\r\n } catch (error) {\r\n clearTimeout(timeoutId);\r\n\r\n if (error instanceof NetworkError) {\r\n throw error;\r\n }\r\n\r\n if (error instanceof Error && error.name === \"AbortError\") {\r\n throw new NetworkError(\"Request timeout\", undefined, error);\r\n }\r\n\r\n throw new NetworkError(\"Network request failed\", undefined, error);\r\n }\r\n }\r\n\r\n /**\r\n * POST request with form data (for OAuth token exchange)\r\n */\r\n async postForm<T>(\r\n endpoint: string,\r\n data: Record<string, string>,\r\n headers: Record<string, string> = {},\r\n ): Promise<T> {\r\n const url = `${this.baseUrl}${endpoint}`;\r\n const controller = new AbortController();\r\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\r\n\r\n try {\r\n const response = await fetch(url, {\r\n method: \"POST\",\r\n headers: {\r\n \"Content-Type\": \"application/x-www-form-urlencoded\",\r\n ...headers,\r\n },\r\n body: new URLSearchParams(data).toString(),\r\n signal: controller.signal,\r\n });\r\n\r\n clearTimeout(timeoutId);\r\n\r\n if (!response.ok) {\r\n throw NetworkError.fromResponse(response);\r\n }\r\n\r\n return await response.json();\r\n } catch (error) {\r\n clearTimeout(timeoutId);\r\n\r\n if (error instanceof NetworkError) {\r\n throw error;\r\n }\r\n\r\n throw new NetworkError(\"Network request failed\", undefined, error);\r\n }\r\n }\r\n}\r\n\r\nexport { AuthError, ConfigError, GenationError, NetworkError } from \"./errors\";\r\n","import type { PKCEChallenge } from \"../types\";\r\n\r\n/**\r\n * Base64URL encode a buffer (matches Supabase implementation)\r\n */\r\nfunction base64URLEncode(buffer: Uint8Array): string {\r\n return btoa(String.fromCharCode(...buffer))\r\n .replace(/\\+/g, \"-\")\r\n .replace(/\\//g, \"_\")\r\n .replace(/=/g, \"\");\r\n}\r\n\r\n/**\r\n * Generate a random code verifier (43-128 characters)\r\n * Matches Supabase implementation\r\n */\r\nfunction generateCodeVerifier(): string {\r\n const array = new Uint8Array(32);\r\n crypto.getRandomValues(array);\r\n return base64URLEncode(array);\r\n}\r\n\r\n/**\r\n * Create code challenge from verifier using SHA-256\r\n * Matches Supabase implementation\r\n */\r\nasync function generateCodeChallenge(verifier: string): Promise<string> {\r\n const encoder = new TextEncoder();\r\n const data = encoder.encode(verifier);\r\n const hash = await crypto.subtle.digest(\"SHA-256\", data);\r\n return base64URLEncode(new Uint8Array(hash));\r\n}\r\n\r\n/**\r\n * Generate PKCE code verifier and challenge pair\r\n * Uses S256 method as required by OAuth 2.1\r\n */\r\nexport async function generatePKCE(): Promise<PKCEChallenge> {\r\n const codeVerifier = generateCodeVerifier();\r\n const codeChallenge = await generateCodeChallenge(codeVerifier);\r\n\r\n return {\r\n codeVerifier,\r\n codeChallenge,\r\n codeChallengeMethod: \"S256\",\r\n };\r\n}\r\n\r\n/**\r\n * Generate random state parameter for CSRF protection\r\n */\r\nexport function generateState(): string {\r\n const array = new Uint8Array(16);\r\n crypto.getRandomValues(array);\r\n return base64URLEncode(array);\r\n}\r\n","import type { TokenSet, TokenStorage } from \"../types\";\r\n\r\nconst TOKEN_KEY = \"tokens\";\r\nconst PKCE_KEY = \"pkce\";\r\nconst STATE_KEY = \"state\";\r\n\r\n/**\r\n * Manages token lifecycle: storage, retrieval, refresh\r\n */\r\nexport class TokenManager {\r\n private storage: TokenStorage;\r\n\r\n constructor(storage: TokenStorage) {\r\n this.storage = storage;\r\n }\r\n\r\n /**\r\n * Store token set\r\n */\r\n async setTokens(tokens: TokenSet): Promise<void> {\r\n await this.storage.set(TOKEN_KEY, JSON.stringify(tokens));\r\n }\r\n\r\n /**\r\n * Get stored tokens\r\n */\r\n async getTokens(): Promise<TokenSet | null> {\r\n const data = await this.storage.get(TOKEN_KEY);\r\n if (!data) return null;\r\n\r\n try {\r\n return JSON.parse(data) as TokenSet;\r\n } catch {\r\n return null;\r\n }\r\n }\r\n\r\n /**\r\n * Clear stored tokens\r\n */\r\n async clearTokens(): Promise<void> {\r\n await this.storage.remove(TOKEN_KEY);\r\n }\r\n\r\n /**\r\n * Check if access token is expired\r\n */\r\n async isTokenExpired(): Promise<boolean> {\r\n const tokens = await this.getTokens();\r\n if (!tokens) return true;\r\n\r\n const expiresAt = tokens.issuedAt + tokens.expiresIn * 1000;\r\n // Consider expired if less than 60 seconds remaining\r\n return Date.now() > expiresAt - 60000;\r\n }\r\n\r\n /**\r\n * Store PKCE verifier for later validation\r\n */\r\n async setPKCE(codeVerifier: string): Promise<void> {\r\n await this.storage.set(PKCE_KEY, codeVerifier);\r\n }\r\n\r\n /**\r\n * Get and clear stored PKCE verifier\r\n */\r\n async consumePKCE(): Promise<string | null> {\r\n const verifier = await this.storage.get(PKCE_KEY);\r\n if (verifier) {\r\n await this.storage.remove(PKCE_KEY);\r\n }\r\n return verifier;\r\n }\r\n\r\n /**\r\n * Store state for CSRF validation\r\n */\r\n async setState(state: string): Promise<void> {\r\n await this.storage.set(STATE_KEY, state);\r\n }\r\n\r\n /**\r\n * Get and clear stored state\r\n */\r\n async consumeState(): Promise<string | null> {\r\n const state = await this.storage.get(STATE_KEY);\r\n if (state) {\r\n await this.storage.remove(STATE_KEY);\r\n }\r\n return state;\r\n }\r\n\r\n /**\r\n * Clear all auth-related data\r\n */\r\n async clearAll(): Promise<void> {\r\n await this.storage.clear();\r\n }\r\n}\r\n","import type { GenationConfig, TokenSet } from \"../types\";\r\nimport { AuthError, HttpClient } from \"../http\";\r\nimport { generatePKCE, generateState } from \"./pkce\";\r\nimport { TokenManager } from \"./token-manager\";\r\n\r\nconst DEFAULT_AUTH_URL = \"https://mnnoheowoowbtpuoguul.supabase.co/auth/v1\";\r\n\r\ninterface TokenResponse {\r\n access_token: string;\r\n refresh_token?: string;\r\n token_type: string;\r\n expires_in: number;\r\n scope?: string;\r\n}\r\n\r\n/**\r\n * OAuth 2.1 handler with PKCE support\r\n */\r\nexport class OAuth2Handler {\r\n private config:\r\n & Required<\r\n Pick<GenationConfig, \"clientId\" | \"clientSecret\" | \"redirectUri\">\r\n >\r\n & Pick<GenationConfig, \"scopes\" | \"authUrl\">;\r\n private http: HttpClient;\r\n private tokenManager: TokenManager;\r\n\r\n constructor(\r\n config: GenationConfig,\r\n tokenManager: TokenManager,\r\n ) {\r\n this.config = {\r\n clientId: config.clientId,\r\n clientSecret: config.clientSecret,\r\n redirectUri: config.redirectUri,\r\n scopes: config.scopes,\r\n authUrl: config.authUrl ?? DEFAULT_AUTH_URL,\r\n };\r\n this.http = new HttpClient({ baseUrl: this.config.authUrl! });\r\n this.tokenManager = tokenManager;\r\n }\r\n\r\n /**\r\n * Generate authorization URL for OAuth flow\r\n * Stores PKCE verifier and state for later validation\r\n */\r\n async getAuthorizationUrl(): Promise<string> {\r\n const pkce = await generatePKCE();\r\n const state = generateState();\r\n\r\n // Store for later validation\r\n await this.tokenManager.setPKCE(pkce.codeVerifier);\r\n await this.tokenManager.setState(state);\r\n\r\n const params = new URLSearchParams({\r\n response_type: \"code\",\r\n client_id: this.config.clientId,\r\n redirect_uri: this.config.redirectUri,\r\n state,\r\n code_challenge: pkce.codeChallenge,\r\n code_challenge_method: pkce.codeChallengeMethod,\r\n });\r\n\r\n if (this.config.scopes && this.config.scopes.length > 0) {\r\n params.append(\"scope\", this.config.scopes.join(\" \"));\r\n }\r\n\r\n return `${this.config.authUrl}/oauth/authorize?${params.toString()}`;\r\n }\r\n\r\n /**\r\n * Exchange authorization code for tokens\r\n */\r\n async exchangeCode(code: string, state: string): Promise<TokenSet> {\r\n // Validate state\r\n const storedState = await this.tokenManager.consumeState();\r\n if (!storedState || storedState !== state) {\r\n throw AuthError.invalidState();\r\n }\r\n\r\n // Get PKCE verifier\r\n const codeVerifier = await this.tokenManager.consumePKCE();\r\n if (!codeVerifier) {\r\n throw AuthError.pkceVerificationFailed(\"Missing code verifier\");\r\n }\r\n\r\n // Exchange code for tokens\r\n const response = await this.http.postForm<TokenResponse>(\r\n \"/oauth/token\",\r\n {\r\n grant_type: \"authorization_code\",\r\n code,\r\n redirect_uri: this.config.redirectUri,\r\n client_id: this.config.clientId,\r\n client_secret: this.config.clientSecret,\r\n code_verifier: codeVerifier,\r\n },\r\n );\r\n\r\n const tokens = this.mapTokenResponse(response);\r\n await this.tokenManager.setTokens(tokens);\r\n\r\n return tokens;\r\n }\r\n\r\n /**\r\n * Refresh access token using refresh token\r\n */\r\n async refreshToken(): Promise<TokenSet> {\r\n const currentTokens = await this.tokenManager.getTokens();\r\n if (!currentTokens?.refreshToken) {\r\n throw AuthError.invalidGrant(\"No refresh token available\");\r\n }\r\n\r\n const response = await this.http.postForm<TokenResponse>(\r\n \"/oauth/token\",\r\n {\r\n grant_type: \"refresh_token\",\r\n refresh_token: currentTokens.refreshToken,\r\n client_id: this.config.clientId,\r\n client_secret: this.config.clientSecret,\r\n },\r\n );\r\n\r\n const tokens = this.mapTokenResponse(response);\r\n await this.tokenManager.setTokens(tokens);\r\n\r\n return tokens;\r\n }\r\n\r\n /**\r\n * Revoke current tokens\r\n */\r\n async revokeToken(): Promise<void> {\r\n const tokens = await this.tokenManager.getTokens();\r\n if (!tokens) return;\r\n\r\n try {\r\n await this.http.postForm(\"/oauth/revoke\", {\r\n token: tokens.accessToken,\r\n client_id: this.config.clientId,\r\n client_secret: this.config.clientSecret,\r\n });\r\n } finally {\r\n await this.tokenManager.clearTokens();\r\n }\r\n }\r\n\r\n /**\r\n * Map OAuth token response to TokenSet\r\n */\r\n private mapTokenResponse(response: TokenResponse): TokenSet {\r\n return {\r\n accessToken: response.access_token,\r\n refreshToken: response.refresh_token,\r\n tokenType: response.token_type,\r\n expiresIn: response.expires_in,\r\n issuedAt: Date.now(),\r\n scope: response.scope,\r\n };\r\n }\r\n}\r\n","import type { TokenStorage } from \"../types\";\r\n\r\n/**\r\n * In-memory storage implementation\r\n * Tokens are lost when page refreshes\r\n */\r\nexport class MemoryStorage implements TokenStorage {\r\n private store = new Map<string, string>();\r\n\r\n async get(key: string): Promise<string | null> {\r\n return this.store.get(key) ?? null;\r\n }\r\n\r\n async set(key: string, value: string): Promise<void> {\r\n this.store.set(key, value);\r\n }\r\n\r\n async remove(key: string): Promise<void> {\r\n this.store.delete(key);\r\n }\r\n\r\n async clear(): Promise<void> {\r\n this.store.clear();\r\n }\r\n}\r\n","import type { TokenStorage } from \"../types\";\r\n\r\n/**\r\n * Browser localStorage implementation\r\n * Tokens persist across browser sessions\r\n */\r\nexport class LocalStorage implements TokenStorage {\r\n private prefix: string;\r\n\r\n constructor(prefix = \"genation\") {\r\n this.prefix = prefix;\r\n }\r\n\r\n private getKey(key: string): string {\r\n return `${this.prefix}:${key}`;\r\n }\r\n\r\n async get(key: string): Promise<string | null> {\r\n if (typeof window === \"undefined\") return null;\r\n return localStorage.getItem(this.getKey(key));\r\n }\r\n\r\n async set(key: string, value: string): Promise<void> {\r\n if (typeof window === \"undefined\") return;\r\n localStorage.setItem(this.getKey(key), value);\r\n }\r\n\r\n async remove(key: string): Promise<void> {\r\n if (typeof window === \"undefined\") return;\r\n localStorage.removeItem(this.getKey(key));\r\n }\r\n\r\n async clear(): Promise<void> {\r\n if (typeof window === \"undefined\") return;\r\n const keys = Object.keys(localStorage).filter((k) =>\r\n k.startsWith(`${this.prefix}:`)\r\n );\r\n keys.forEach((k) => localStorage.removeItem(k));\r\n }\r\n}\r\n","import type { TokenStorage } from \"../types\";\r\n\r\n/**\r\n * Browser sessionStorage implementation\r\n * Tokens persist until browser tab is closed\r\n */\r\nexport class SessionStorage implements TokenStorage {\r\n private prefix: string;\r\n\r\n constructor(prefix = \"genation\") {\r\n this.prefix = prefix;\r\n }\r\n\r\n private getKey(key: string): string {\r\n return `${this.prefix}:${key}`;\r\n }\r\n\r\n async get(key: string): Promise<string | null> {\r\n if (typeof window === \"undefined\") return null;\r\n return sessionStorage.getItem(this.getKey(key));\r\n }\r\n\r\n async set(key: string, value: string): Promise<void> {\r\n if (typeof window === \"undefined\") return;\r\n sessionStorage.setItem(this.getKey(key), value);\r\n }\r\n\r\n async remove(key: string): Promise<void> {\r\n if (typeof window === \"undefined\") return;\r\n sessionStorage.removeItem(this.getKey(key));\r\n }\r\n\r\n async clear(): Promise<void> {\r\n if (typeof window === \"undefined\") return;\r\n const keys = Object.keys(sessionStorage).filter((k) =>\r\n k.startsWith(`${this.prefix}:`)\r\n );\r\n keys.forEach((k) => sessionStorage.removeItem(k));\r\n }\r\n}\r\n","/**\r\n * @fileoverview Storage factory and implementations\r\n * @module storage\r\n */\r\n\r\nimport type { StorageType, TokenStorage } from \"../types\";\r\nimport { MemoryStorage } from \"./memory\";\r\nimport { LocalStorage } from \"./local-storage\";\r\nimport { SessionStorage } from \"./session-storage\";\r\n\r\nexport { MemoryStorage } from \"./memory\";\r\nexport { LocalStorage } from \"./local-storage\";\r\nexport { SessionStorage } from \"./session-storage\";\r\n\r\n/**\r\n * Create a storage instance based on type\r\n *\r\n * @param type - Storage type to create\r\n * @returns Storage implementation\r\n *\r\n * @example\r\n * ```typescript\r\n * const storage = createStorage('localStorage');\r\n * await storage.set('key', 'value');\r\n * ```\r\n */\r\nexport function createStorage(\r\n type: StorageType = \"localStorage\",\r\n): TokenStorage {\r\n switch (type) {\r\n case \"memory\":\r\n return new MemoryStorage();\r\n case \"localStorage\":\r\n return new LocalStorage();\r\n case \"sessionStorage\":\r\n return new SessionStorage();\r\n default:\r\n return new LocalStorage();\r\n }\r\n}\r\n","// Function to convert snake_case to camelCase, handles arrays and objects recursively\r\nexport function snakeToCamel(data: any): any {\r\n if (Array.isArray(data)) {\r\n return data.map(snakeToCamel);\r\n } else if (typeof data === \"object\" && data !== null) {\r\n return Object.fromEntries(\r\n Object.entries(data).map(([key, value]) => [\r\n key.replace(/_([a-z])/g, (_, c) => c.toUpperCase()),\r\n snakeToCamel(value)\r\n ])\r\n );\r\n }\r\n return data;\r\n}","/**\r\n * @fileoverview Main Genation SDK client\r\n * @module client\r\n */\r\n\r\nimport type {\r\n AuthEvent,\r\n AuthStateChangeCallback,\r\n GenationConfig,\r\n Session,\r\n Subscription,\r\n TokenSet,\r\n TokenStorage,\r\n User,\r\n} from \"./types\";\r\nimport { OAuth2Handler, TokenManager } from \"./auth\";\r\nimport { createStorage } from \"./storage\";\r\nimport { ConfigError, HttpClient } from \"./http\";\r\nimport type { License, LicenseResponse } from \"./types/server/license\";\r\nimport type { ApiResponse } from \"./types/server/api-response\";\r\nimport { snakeToCamel } from \"./utils/converter\";\r\n\r\n// Re-export types for convenience\r\nexport type { AuthEvent, AuthStateChangeCallback, Session, Subscription };\r\n\r\n/**\r\n * Main Genation SDK client\r\n *\r\n * OAuth 2.1 authentication client for Genation platform.\r\n * Supports PKCE flow and automatic token refresh.\r\n *\r\n * @example\r\n * ```typescript\r\n * import { createClient } from 'genation';\r\n *\r\n * const client = createClient({\r\n * clientId: 'your-client-id',\r\n * clientSecret: 'your-client-secret',\r\n * redirectUri: 'http://localhost:3000/callback'\r\n * });\r\n *\r\n * // Listen to auth state changes\r\n * const { subscription } = client.onAuthStateChange((event, session) => {\r\n * if (event === 'SIGNED_IN') {\r\n * console.log('User signed in:', session?.user);\r\n * }\r\n * });\r\n *\r\n * // Start login flow\r\n * window.location.href = await client.signIn();\r\n * ```\r\n */\r\nexport class GenationClient {\r\n private oauth: OAuth2Handler;\r\n private tokenManager: TokenManager;\r\n private http: HttpClient;\r\n private httpServer: HttpClient;\r\n private listeners: Set<AuthStateChangeCallback> = new Set();\r\n private initialized = false;\r\n\r\n constructor(config: GenationConfig) {\r\n this.validateConfig(config);\r\n\r\n const storage: TokenStorage = typeof config.storage === \"object\"\r\n ? (config.storage as unknown as TokenStorage)\r\n : createStorage(config.storage);\r\n\r\n this.tokenManager = new TokenManager(storage);\r\n this.oauth = new OAuth2Handler(config, this.tokenManager);\r\n this.http = new HttpClient({\r\n baseUrl: config.authUrl ??\r\n \"https://mnnoheowoowbtpuoguul.supabase.co/auth/v1\",\r\n });\r\n this.httpServer = new HttpClient({\r\n baseUrl: \"https://ff-api.genation.ai/api/v2/client\"\r\n });\r\n }\r\n\r\n private validateConfig(config: GenationConfig): void {\r\n if (!config.clientId) throw ConfigError.missingField(\"clientId\");\r\n if (!config.clientSecret) {\r\n throw ConfigError.missingField(\"clientSecret\");\r\n }\r\n if (!config.redirectUri) throw ConfigError.missingField(\"redirectUri\");\r\n }\r\n\r\n /**\r\n * Emit auth state change event to all listeners\r\n */\r\n private async emitAuthStateChange(event: AuthEvent): Promise<void> {\r\n const session = await this.getSession();\r\n this.listeners.forEach((callback) => {\r\n try {\r\n callback(event, session);\r\n } catch (error) {\r\n console.error(\"Error in auth state change callback:\", error);\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Listen to authentication state changes\r\n *\r\n * Register a callback that fires when:\r\n * - `INITIAL_SESSION`: On first subscription, with current session state\r\n * - `SIGNED_IN`: User successfully authenticated\r\n * - `SIGNED_OUT`: User logged out or session expired\r\n * - `TOKEN_REFRESHED`: Access token was automatically refreshed\r\n *\r\n * @param callback - Function called on each auth state change\r\n * @returns Object containing subscription with `unsubscribe()` method\r\n *\r\n * @example\r\n * ```typescript\r\n * const { subscription } = client.onAuthStateChange((event, session) => {\r\n * console.log('Auth event:', event);\r\n *\r\n * if (event === 'INITIAL_SESSION') {\r\n * // Check if user was previously logged in\r\n * if (session) {\r\n * console.log('Welcome back!', session.user);\r\n * }\r\n * } else if (event === 'SIGNED_IN') {\r\n * // User just signed in\r\n * console.log('Signed in:', session?.user);\r\n * } else if (event === 'SIGNED_OUT') {\r\n * // Clear app state, redirect to login\r\n * console.log('Signed out');\r\n * }\r\n * });\r\n *\r\n * // Cleanup when component unmounts\r\n * subscription.unsubscribe();\r\n * ```\r\n */\r\n onAuthStateChange(\r\n callback: AuthStateChangeCallback,\r\n ): { subscription: Subscription } {\r\n this.listeners.add(callback);\r\n\r\n // Emit INITIAL_SESSION on first subscription\r\n if (!this.initialized) {\r\n this.initialized = true;\r\n setTimeout(() => {\r\n this.emitAuthStateChange(\"INITIAL_SESSION\");\r\n }, 0);\r\n } else {\r\n // For subsequent subscriptions, also emit current state\r\n setTimeout(() => {\r\n this.emitAuthStateChange(\"INITIAL_SESSION\");\r\n }, 0);\r\n }\r\n\r\n return {\r\n subscription: {\r\n unsubscribe: () => {\r\n this.listeners.delete(callback);\r\n },\r\n },\r\n };\r\n }\r\n\r\n /**\r\n * Start OAuth sign-in flow\r\n *\r\n * Generates authorization URL with PKCE challenge.\r\n * Redirect user to this URL to start authentication.\r\n *\r\n * @returns Authorization URL to redirect user to\r\n *\r\n * @example\r\n * ```typescript\r\n * async function handleLogin() {\r\n * const url = await client.signIn();\r\n * window.location.href = url;\r\n * }\r\n * ```\r\n */\r\n async signIn(): Promise<string> {\r\n return this.oauth.getAuthorizationUrl();\r\n }\r\n\r\n /**\r\n * Handle OAuth callback after user authentication\r\n *\r\n * Call this on your redirect URI page to exchange\r\n * the authorization code for access tokens.\r\n * Triggers `SIGNED_IN` event on success.\r\n *\r\n * @param code - Authorization code from URL query params\r\n * @param state - State parameter for CSRF validation\r\n * @returns Token set with access and refresh tokens\r\n * @throws {AuthError} If state mismatch or code exchange fails\r\n *\r\n * @example\r\n * ```typescript\r\n * // On your /callback page\r\n * async function handleCallback() {\r\n * const url = window.location.href;\r\n * await client.handleCallback(url);\r\n * // onAuthStateChange will fire with SIGNED_IN event\r\n * }\r\n * ```\r\n */\r\n async handleCallback(url: string): Promise<TokenSet> {\r\n const params = new URLSearchParams(url);\r\n const code = params.get('code');\r\n const state = params.get('state');\r\n if (!code || !state) {\r\n throw new Error('Missing code or state');\r\n }\r\n const tokens = await this.oauth.exchangeCode(code, state);\r\n await this.emitAuthStateChange(\"SIGNED_IN\");\r\n return tokens;\r\n }\r\n\r\n // /**\r\n // * Sign out and revoke tokens\r\n // *\r\n // * Clears local session and revokes tokens on server.\r\n // * Triggers `SIGNED_OUT` event for all listeners.\r\n // *\r\n // * @example\r\n // * ```typescript\r\n // * async function handleLogout() {\r\n // * await client.signOut();\r\n // * // onAuthStateChange will fire with SIGNED_OUT event\r\n // * }\r\n // * ```\r\n // */\r\n // async signOut(): Promise<void> {\r\n // await this.oauth.revokeToken();\r\n // await this.emitAuthStateChange(\"SIGNED_OUT\");\r\n // }\r\n\r\n /**\r\n * Get current session\r\n *\r\n * Returns session with access token and user info.\r\n * Automatically refreshes token if expired.\r\n *\r\n * @returns Current session or null if not authenticated\r\n *\r\n * @example\r\n * ```typescript\r\n * const session = await client.getSession();\r\n * if (session) {\r\n * console.log('Logged in as:', session.user?.email);\r\n *\r\n * // Use access token for API calls\r\n * fetch('/api/data', {\r\n * headers: { Authorization: `Bearer ${session.accessToken}` }\r\n * });\r\n * }\r\n * ```\r\n */\r\n async getSession(): Promise<Session | null> {\r\n const isExpired = await this.tokenManager.isTokenExpired();\r\n\r\n if (isExpired) {\r\n try {\r\n await this.oauth.refreshToken();\r\n } catch {\r\n return null;\r\n }\r\n }\r\n\r\n const tokens = await this.tokenManager.getTokens();\r\n if (!tokens) return null;\r\n\r\n const user = await this.fetchUser(tokens.accessToken);\r\n\r\n return {\r\n accessToken: tokens.accessToken,\r\n refreshToken: tokens.refreshToken,\r\n expiresIn: tokens.expiresIn,\r\n expiresAt: tokens.issuedAt + tokens.expiresIn * 1000,\r\n user,\r\n };\r\n }\r\n /**\r\n * Get licenses\r\n * @param accessToken - The access token to use for the request\r\n * @param options - The options for the request\r\n * @param options.expiresAfter - Query licenses that are expired after the given date, default set to today to get all valid licenses (unexpired licenses)\r\n * @returns The licenses\r\n */\r\n async getLicenses(options: { expiresAfter?: Date } = {}): Promise<License[] | null> {\r\n const session = await this.getSession();\r\n if (!session) {\r\n return null;\r\n }\r\n const accessToken = session.accessToken;\r\n const { expiresAfter = new Date() } = options;\r\n const response = await this.httpServer.request<ApiResponse<LicenseResponse[]>>(\"/licenses\", {\r\n headers: { Authorization: `Bearer ${accessToken}` },\r\n params: { expiresAfter: expiresAfter.toISOString() }\r\n });\r\n if (!response.ok) {\r\n console.error(\"GenationClient: Error fetching licenses:\", response.error);\r\n return null;\r\n }\r\n const licenses: License[] = snakeToCamel(response.data);\r\n return licenses;\r\n }\r\n /**\r\n * Fetch user info from auth server\r\n */\r\n private async fetchUser(accessToken: string): Promise<User | null> {\r\n try {\r\n // Use standard OIDC UserInfo endpoint\r\n // https://supabase.com/docs/guides/auth/oauth-server/oauth-flows#userinfo-endpoint\r\n const response = await this.http.request<{\r\n sub: string;\r\n email?: string;\r\n name?: string;\r\n picture?: string;\r\n email_verified?: boolean;\r\n phone_number?: string;\r\n phone_number_verified?: boolean;\r\n }>(\"/oauth/userinfo\", {\r\n headers: { Authorization: `Bearer ${accessToken}` },\r\n });\r\n\r\n return {\r\n sub: response.sub,\r\n name: response.name,\r\n picture: response.picture,\r\n email: response.email,\r\n email_verified: response.email_verified,\r\n phone_number: response.phone_number,\r\n phone_number_verified: response.phone_number_verified,\r\n };\r\n } catch (error) {\r\n console.error(\"GenationClient: Error fetching user:\", error);\r\n return null;\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Create a new Genation client instance\r\n *\r\n * Factory function for creating SDK client with configuration.\r\n *\r\n * @param config - Client configuration options\r\n * @returns Configured GenationClient instance\r\n *\r\n * @example\r\n * ```typescript\r\n * import { createClient } from 'genation';\r\n *\r\n * const client = createClient({\r\n * clientId: 'your-client-id',\r\n * clientSecret: 'your-client-secret',\r\n * redirectUri: 'http://localhost:3000/callback',\r\n * // Optional\r\n * scopes: ['openid', 'profile', 'email'],\r\n * storage: 'localStorage',\r\n * });\r\n * ```\r\n */\r\nexport function createClient(config: GenationConfig): GenationClient {\r\n return new GenationClient(config);\r\n}\r\n"],"names":["GenationError","message","code","cause","AuthError","NetworkError","status","response","ConfigError","field","HttpClient","config","endpoint","options","method","headers","body","params","url","searchParams","controller","timeoutId","error","data","base64URLEncode","buffer","generateCodeVerifier","array","generateCodeChallenge","verifier","hash","generatePKCE","codeVerifier","codeChallenge","generateState","TOKEN_KEY","PKCE_KEY","STATE_KEY","TokenManager","storage","tokens","expiresAt","state","DEFAULT_AUTH_URL","OAuth2Handler","tokenManager","pkce","storedState","currentTokens","MemoryStorage","key","value","LocalStorage","prefix","k","SessionStorage","createStorage","type","snakeToCamel","_","c","GenationClient","event","session","callback","user","accessToken","expiresAfter","createClient"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- (function(i,d){typeof exports=="object"&&typeof module<"u"?d(exports):typeof define=="function"&&define.amd?define(["exports"],d):(i=typeof globalThis<"u"?globalThis:i||self,d(i.Genation={}))})(this,(function(i){"use strict";class d extends Error{code;cause;constructor(e,t,r){super(e),this.name="GenationError",this.code=t,this.cause=r}}class h extends d{constructor(e,t,r){super(e,t,r),this.name="AuthError"}static invalidGrant(e="Invalid authorization code or refresh token"){return new h(e,"invalid_grant")}static accessDenied(e="User denied access"){return new h(e,"access_denied")}static expiredToken(e="Token has expired"){return new h(e,"expired_token")}static invalidState(e="State mismatch, possible CSRF attack"){return new h(e,"invalid_state")}static pkceVerificationFailed(e="PKCE verification failed"){return new h(e,"pkce_verification_failed")}}class l extends d{status;constructor(e,t,r){super(e,"network_error",r),this.name="NetworkError",this.status=t}static fromResponse(e){return new l(`HTTP ${e.status}: ${e.statusText}`,e.status)}}class f extends d{constructor(e){super(e,"config_error"),this.name="ConfigError"}static missingField(e){return new f(`Missing required config field: ${e}`)}}class g{baseUrl;timeout;constructor(e){this.baseUrl=e.baseUrl.replace(/\/$/,""),this.timeout=e.timeout??3e4}async request(e,t={}){const{method:r="GET",headers:s={},body:o,params:c}=t;let u=`${this.baseUrl}${e}`;if(c){const a=new URLSearchParams(c);u+=`?${a.toString()}`}const v=new AbortController,E=setTimeout(()=>v.abort(),this.timeout);try{const a=await fetch(u,{method:r,headers:{"Content-Type":"application/json",...s},body:o?JSON.stringify(o):void 0,signal:v.signal});if(clearTimeout(E),!a.ok)throw l.fromResponse(a);return await a.json()}catch(a){throw clearTimeout(E),a instanceof l?a:a instanceof Error&&a.name==="AbortError"?new l("Request timeout",void 0,a):new l("Network request failed",void 0,a)}}async postForm(e,t,r={}){const s=`${this.baseUrl}${e}`,o=new AbortController,c=setTimeout(()=>o.abort(),this.timeout);try{const u=await fetch(s,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded",...r},body:new URLSearchParams(t).toString(),signal:o.signal});if(clearTimeout(c),!u.ok)throw l.fromResponse(u);return await u.json()}catch(u){throw clearTimeout(c),u instanceof l?u:new l("Network request failed",void 0,u)}}}function p(n){return btoa(String.fromCharCode(...n)).replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}function U(){const n=new Uint8Array(32);return crypto.getRandomValues(n),p(n)}async function I(n){const t=new TextEncoder().encode(n),r=await crypto.subtle.digest("SHA-256",t);return p(new Uint8Array(r))}async function A(){const n=U(),e=await I(n);return{codeVerifier:n,codeChallenge:e,codeChallengeMethod:"S256"}}function x(){const n=new Uint8Array(16);return crypto.getRandomValues(n),p(n)}const w="tokens",m="pkce",y="state";class M{storage;constructor(e){this.storage=e}async setTokens(e){await this.storage.set(w,JSON.stringify(e))}async getTokens(){const e=await this.storage.get(w);if(!e)return null;try{return JSON.parse(e)}catch{return null}}async clearTokens(){await this.storage.remove(w)}async isTokenExpired(){const e=await this.getTokens();if(!e)return!0;const t=e.issuedAt+e.expiresIn*1e3;return Date.now()>t-6e4}async setPKCE(e){await this.storage.set(m,e)}async consumePKCE(){const e=await this.storage.get(m);return e&&await this.storage.remove(m),e}async setState(e){await this.storage.set(y,e)}async consumeState(){const e=await this.storage.get(y);return e&&await this.storage.remove(y),e}async clearAll(){await this.storage.clear()}}const K="https://mnnoheowoowbtpuoguul.supabase.co/auth/v1";class ${config;http;tokenManager;constructor(e,t){this.config={clientId:e.clientId,clientSecret:e.clientSecret,redirectUri:e.redirectUri,scopes:e.scopes,authUrl:e.authUrl??K},this.http=new g({baseUrl:this.config.authUrl}),this.tokenManager=t}async getAuthorizationUrl(){const e=await A(),t=x();await this.tokenManager.setPKCE(e.codeVerifier),await this.tokenManager.setState(t);const r=new URLSearchParams({response_type:"code",client_id:this.config.clientId,redirect_uri:this.config.redirectUri,state:t,code_challenge:e.codeChallenge,code_challenge_method:e.codeChallengeMethod});return this.config.scopes&&this.config.scopes.length>0&&r.append("scope",this.config.scopes.join(" ")),`${this.config.authUrl}/oauth/authorize?${r.toString()}`}async exchangeCode(e,t){const r=await this.tokenManager.consumeState();if(!r||r!==t)throw h.invalidState();const s=await this.tokenManager.consumePKCE();if(!s)throw h.pkceVerificationFailed("Missing code verifier");const o=await this.http.postForm("/oauth/token",{grant_type:"authorization_code",code:e,redirect_uri:this.config.redirectUri,client_id:this.config.clientId,client_secret:this.config.clientSecret,code_verifier:s}),c=this.mapTokenResponse(o);return await this.tokenManager.setTokens(c),c}async refreshToken(){const e=await this.tokenManager.getTokens();if(!e?.refreshToken)throw h.invalidGrant("No refresh token available");const t=await this.http.postForm("/oauth/token",{grant_type:"refresh_token",refresh_token:e.refreshToken,client_id:this.config.clientId,client_secret:this.config.clientSecret}),r=this.mapTokenResponse(t);return await this.tokenManager.setTokens(r),r}async revokeToken(){const e=await this.tokenManager.getTokens();if(e)try{await this.http.postForm("/oauth/revoke",{token:e.accessToken,client_id:this.config.clientId,client_secret:this.config.clientSecret})}finally{await this.tokenManager.clearTokens()}}mapTokenResponse(e){return{accessToken:e.access_token,refreshToken:e.refresh_token,tokenType:e.token_type,expiresIn:e.expires_in,issuedAt:Date.now(),scope:e.scope}}}class T{store=new Map;async get(e){return this.store.get(e)??null}async set(e,t){this.store.set(e,t)}async remove(e){this.store.delete(e)}async clear(){this.store.clear()}}class k{prefix;constructor(e="genation"){this.prefix=e}getKey(e){return`${this.prefix}:${e}`}async get(e){return typeof window>"u"?null:localStorage.getItem(this.getKey(e))}async set(e,t){typeof window>"u"||localStorage.setItem(this.getKey(e),t)}async remove(e){typeof window>"u"||localStorage.removeItem(this.getKey(e))}async clear(){if(typeof window>"u")return;Object.keys(localStorage).filter(t=>t.startsWith(`${this.prefix}:`)).forEach(t=>localStorage.removeItem(t))}}class b{prefix;constructor(e="genation"){this.prefix=e}getKey(e){return`${this.prefix}:${e}`}async get(e){return typeof window>"u"?null:sessionStorage.getItem(this.getKey(e))}async set(e,t){typeof window>"u"||sessionStorage.setItem(this.getKey(e),t)}async remove(e){typeof window>"u"||sessionStorage.removeItem(this.getKey(e))}async clear(){if(typeof window>"u")return;Object.keys(sessionStorage).filter(t=>t.startsWith(`${this.prefix}:`)).forEach(t=>sessionStorage.removeItem(t))}}function C(n="localStorage"){switch(n){case"memory":return new T;case"localStorage":return new k;case"sessionStorage":return new b;default:return new k}}function S(n){return Array.isArray(n)?n.map(S):typeof n=="object"&&n!==null?Object.fromEntries(Object.entries(n).map(([e,t])=>[e.replace(/_([a-z])/g,(r,s)=>s.toUpperCase()),S(t)])):n}class _{oauth;tokenManager;http;httpServer;listeners=new Set;initialized=!1;constructor(e){this.validateConfig(e);const t=typeof e.storage=="object"?e.storage:C(e.storage);this.tokenManager=new M(t),this.oauth=new $(e,this.tokenManager),this.http=new g({baseUrl:e.authUrl??"https://mnnoheowoowbtpuoguul.supabase.co/auth/v1"}),this.httpServer=new g({baseUrl:"https://ff-api.genation.ai/api/v2/client"})}validateConfig(e){if(!e.clientId)throw f.missingField("clientId");if(!e.clientSecret)throw f.missingField("clientSecret");if(!e.redirectUri)throw f.missingField("redirectUri")}async emitAuthStateChange(e){const t=await this.getSession();this.listeners.forEach(r=>{try{r(e,t)}catch(s){console.error("Error in auth state change callback:",s)}})}onAuthStateChange(e){return this.listeners.add(e),this.initialized?setTimeout(()=>{this.emitAuthStateChange("INITIAL_SESSION")},0):(this.initialized=!0,setTimeout(()=>{this.emitAuthStateChange("INITIAL_SESSION")},0)),{subscription:{unsubscribe:()=>{this.listeners.delete(e)}}}}async signIn(){return this.oauth.getAuthorizationUrl()}async handleCallback(e,t){const r=await this.oauth.exchangeCode(e,t);try{const s=await this.fetchUser(r.accessToken);console.log("Debug: handleCallback fetched user:",s)}catch(s){console.error("Debug: handleCallback fetchUser failed:",s)}return await this.emitAuthStateChange("SIGNED_IN"),r}async getSession(){if(await this.tokenManager.isTokenExpired())try{await this.oauth.refreshToken()}catch{return null}const t=await this.tokenManager.getTokens();if(!t)return null;const r=await this.fetchUser(t.accessToken);return{accessToken:t.accessToken,refreshToken:t.refreshToken,expiresIn:t.expiresIn,expiresAt:t.issuedAt+t.expiresIn*1e3,user:r}}async getLicenses(e={}){const t=await this.getSession();if(!t)return null;const r=t.accessToken,{expiresAfter:s=new Date}=e,o=await this.httpServer.request("/licenses",{headers:{Authorization:`Bearer ${r}`},params:{expiresAfter:s.toISOString()}});if(!o.ok)return console.error("GenationClient: Error fetching licenses:",o.error),null;console.log("GenationClient: Response data:",o.data);const c=S(o.data);return console.log("GenationClient: Licenses:",c),c}async fetchUser(e){try{const t=await this.http.request("/oauth/userinfo",{headers:{Authorization:`Bearer ${e}`}});return{sub:t.sub,name:t.name,picture:t.picture,email:t.email,email_verified:t.email_verified,phone_number:t.phone_number,phone_number_verified:t.phone_number_verified}}catch(t){return console.error("GenationClient: Error fetching user:",t),null}}}function R(n){return new _(n)}i.AuthError=h,i.ConfigError=f,i.GenationClient=_,i.GenationError=d,i.LocalStorage=k,i.MemoryStorage=T,i.NetworkError=l,i.SessionStorage=b,i.createClient=R,i.createStorage=C,Object.defineProperty(i,Symbol.toStringTag,{value:"Module"})}));
1
+ (function(s,d){typeof exports=="object"&&typeof module<"u"?d(exports):typeof define=="function"&&define.amd?define(["exports"],d):(s=typeof globalThis<"u"?globalThis:s||self,d(s.Genation={}))})(this,(function(s){"use strict";class d extends Error{code;cause;constructor(e,t,n){super(e),this.name="GenationError",this.code=t,this.cause=n}}class c extends d{constructor(e,t,n){super(e,t,n),this.name="AuthError"}static invalidGrant(e="Invalid authorization code or refresh token"){return new c(e,"invalid_grant")}static accessDenied(e="User denied access"){return new c(e,"access_denied")}static expiredToken(e="Token has expired"){return new c(e,"expired_token")}static invalidState(e="State mismatch, possible CSRF attack"){return new c(e,"invalid_state")}static pkceVerificationFailed(e="PKCE verification failed"){return new c(e,"pkce_verification_failed")}}class h extends d{status;constructor(e,t,n){super(e,"network_error",n),this.name="NetworkError",this.status=t}static fromResponse(e){return new h(`HTTP ${e.status}: ${e.statusText}`,e.status)}}class f extends d{constructor(e){super(e,"config_error"),this.name="ConfigError"}static missingField(e){return new f(`Missing required config field: ${e}`)}}class g{baseUrl;timeout;constructor(e){this.baseUrl=e.baseUrl.replace(/\/$/,""),this.timeout=e.timeout??3e4}async request(e,t={}){const{method:n="GET",headers:i={},body:o,params:u}=t;let l=`${this.baseUrl}${e}`;if(u){const a=new URLSearchParams(u);l+=`?${a.toString()}`}const C=new AbortController,E=setTimeout(()=>C.abort(),this.timeout);try{const a=await fetch(l,{method:n,headers:{"Content-Type":"application/json",...i},body:o?JSON.stringify(o):void 0,signal:C.signal});if(clearTimeout(E),!a.ok)throw h.fromResponse(a);return await a.json()}catch(a){throw clearTimeout(E),a instanceof h?a:a instanceof Error&&a.name==="AbortError"?new h("Request timeout",void 0,a):new h("Network request failed",void 0,a)}}async postForm(e,t,n={}){const i=`${this.baseUrl}${e}`,o=new AbortController,u=setTimeout(()=>o.abort(),this.timeout);try{const l=await fetch(i,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded",...n},body:new URLSearchParams(t).toString(),signal:o.signal});if(clearTimeout(u),!l.ok)throw h.fromResponse(l);return await l.json()}catch(l){throw clearTimeout(u),l instanceof h?l:new h("Network request failed",void 0,l)}}}function p(r){return btoa(String.fromCharCode(...r)).replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}function I(){const r=new Uint8Array(32);return crypto.getRandomValues(r),p(r)}async function U(r){const t=new TextEncoder().encode(r),n=await crypto.subtle.digest("SHA-256",t);return p(new Uint8Array(n))}async function A(){const r=I(),e=await U(r);return{codeVerifier:r,codeChallenge:e,codeChallengeMethod:"S256"}}function x(){const r=new Uint8Array(16);return crypto.getRandomValues(r),p(r)}const w="tokens",m="pkce",y="state";class M{storage;constructor(e){this.storage=e}async setTokens(e){await this.storage.set(w,JSON.stringify(e))}async getTokens(){const e=await this.storage.get(w);if(!e)return null;try{return JSON.parse(e)}catch{return null}}async clearTokens(){await this.storage.remove(w)}async isTokenExpired(){const e=await this.getTokens();if(!e)return!0;const t=e.issuedAt+e.expiresIn*1e3;return Date.now()>t-6e4}async setPKCE(e){await this.storage.set(m,e)}async consumePKCE(){const e=await this.storage.get(m);return e&&await this.storage.remove(m),e}async setState(e){await this.storage.set(y,e)}async consumeState(){const e=await this.storage.get(y);return e&&await this.storage.remove(y),e}async clearAll(){await this.storage.clear()}}const K="https://mnnoheowoowbtpuoguul.supabase.co/auth/v1";class ${config;http;tokenManager;constructor(e,t){this.config={clientId:e.clientId,clientSecret:e.clientSecret,redirectUri:e.redirectUri,scopes:e.scopes,authUrl:e.authUrl??K},this.http=new g({baseUrl:this.config.authUrl}),this.tokenManager=t}async getAuthorizationUrl(){const e=await A(),t=x();await this.tokenManager.setPKCE(e.codeVerifier),await this.tokenManager.setState(t);const n=new URLSearchParams({response_type:"code",client_id:this.config.clientId,redirect_uri:this.config.redirectUri,state:t,code_challenge:e.codeChallenge,code_challenge_method:e.codeChallengeMethod});return this.config.scopes&&this.config.scopes.length>0&&n.append("scope",this.config.scopes.join(" ")),`${this.config.authUrl}/oauth/authorize?${n.toString()}`}async exchangeCode(e,t){const n=await this.tokenManager.consumeState();if(!n||n!==t)throw c.invalidState();const i=await this.tokenManager.consumePKCE();if(!i)throw c.pkceVerificationFailed("Missing code verifier");const o=await this.http.postForm("/oauth/token",{grant_type:"authorization_code",code:e,redirect_uri:this.config.redirectUri,client_id:this.config.clientId,client_secret:this.config.clientSecret,code_verifier:i}),u=this.mapTokenResponse(o);return await this.tokenManager.setTokens(u),u}async refreshToken(){const e=await this.tokenManager.getTokens();if(!e?.refreshToken)throw c.invalidGrant("No refresh token available");const t=await this.http.postForm("/oauth/token",{grant_type:"refresh_token",refresh_token:e.refreshToken,client_id:this.config.clientId,client_secret:this.config.clientSecret}),n=this.mapTokenResponse(t);return await this.tokenManager.setTokens(n),n}async revokeToken(){const e=await this.tokenManager.getTokens();if(e)try{await this.http.postForm("/oauth/revoke",{token:e.accessToken,client_id:this.config.clientId,client_secret:this.config.clientSecret})}finally{await this.tokenManager.clearTokens()}}mapTokenResponse(e){return{accessToken:e.access_token,refreshToken:e.refresh_token,tokenType:e.token_type,expiresIn:e.expires_in,issuedAt:Date.now(),scope:e.scope}}}class T{store=new Map;async get(e){return this.store.get(e)??null}async set(e,t){this.store.set(e,t)}async remove(e){this.store.delete(e)}async clear(){this.store.clear()}}class k{prefix;constructor(e="genation"){this.prefix=e}getKey(e){return`${this.prefix}:${e}`}async get(e){return typeof window>"u"?null:localStorage.getItem(this.getKey(e))}async set(e,t){typeof window>"u"||localStorage.setItem(this.getKey(e),t)}async remove(e){typeof window>"u"||localStorage.removeItem(this.getKey(e))}async clear(){if(typeof window>"u")return;Object.keys(localStorage).filter(t=>t.startsWith(`${this.prefix}:`)).forEach(t=>localStorage.removeItem(t))}}class b{prefix;constructor(e="genation"){this.prefix=e}getKey(e){return`${this.prefix}:${e}`}async get(e){return typeof window>"u"?null:sessionStorage.getItem(this.getKey(e))}async set(e,t){typeof window>"u"||sessionStorage.setItem(this.getKey(e),t)}async remove(e){typeof window>"u"||sessionStorage.removeItem(this.getKey(e))}async clear(){if(typeof window>"u")return;Object.keys(sessionStorage).filter(t=>t.startsWith(`${this.prefix}:`)).forEach(t=>sessionStorage.removeItem(t))}}function _(r="localStorage"){switch(r){case"memory":return new T;case"localStorage":return new k;case"sessionStorage":return new b;default:return new k}}function S(r){return Array.isArray(r)?r.map(S):typeof r=="object"&&r!==null?Object.fromEntries(Object.entries(r).map(([e,t])=>[e.replace(/_([a-z])/g,(n,i)=>i.toUpperCase()),S(t)])):r}class v{oauth;tokenManager;http;httpServer;listeners=new Set;initialized=!1;constructor(e){this.validateConfig(e);const t=typeof e.storage=="object"?e.storage:_(e.storage);this.tokenManager=new M(t),this.oauth=new $(e,this.tokenManager),this.http=new g({baseUrl:e.authUrl??"https://mnnoheowoowbtpuoguul.supabase.co/auth/v1"}),this.httpServer=new g({baseUrl:"https://ff-api.genation.ai/api/v2/client"})}validateConfig(e){if(!e.clientId)throw f.missingField("clientId");if(!e.clientSecret)throw f.missingField("clientSecret");if(!e.redirectUri)throw f.missingField("redirectUri")}async emitAuthStateChange(e){const t=await this.getSession();this.listeners.forEach(n=>{try{n(e,t)}catch(i){console.error("Error in auth state change callback:",i)}})}onAuthStateChange(e){return this.listeners.add(e),this.initialized?setTimeout(()=>{this.emitAuthStateChange("INITIAL_SESSION")},0):(this.initialized=!0,setTimeout(()=>{this.emitAuthStateChange("INITIAL_SESSION")},0)),{subscription:{unsubscribe:()=>{this.listeners.delete(e)}}}}async signIn(){return this.oauth.getAuthorizationUrl()}async handleCallback(e){const t=new URLSearchParams(e),n=t.get("code"),i=t.get("state");if(!n||!i)throw new Error("Missing code or state");const o=await this.oauth.exchangeCode(n,i);return await this.emitAuthStateChange("SIGNED_IN"),o}async getSession(){if(await this.tokenManager.isTokenExpired())try{await this.oauth.refreshToken()}catch{return null}const t=await this.tokenManager.getTokens();if(!t)return null;const n=await this.fetchUser(t.accessToken);return{accessToken:t.accessToken,refreshToken:t.refreshToken,expiresIn:t.expiresIn,expiresAt:t.issuedAt+t.expiresIn*1e3,user:n}}async getLicenses(e={}){const t=await this.getSession();if(!t)return null;const n=t.accessToken,{expiresAfter:i=new Date}=e,o=await this.httpServer.request("/licenses",{headers:{Authorization:`Bearer ${n}`},params:{expiresAfter:i.toISOString()}});return o.ok?S(o.data):(console.error("GenationClient: Error fetching licenses:",o.error),null)}async fetchUser(e){try{const t=await this.http.request("/oauth/userinfo",{headers:{Authorization:`Bearer ${e}`}});return{sub:t.sub,name:t.name,picture:t.picture,email:t.email,email_verified:t.email_verified,phone_number:t.phone_number,phone_number_verified:t.phone_number_verified}}catch(t){return console.error("GenationClient: Error fetching user:",t),null}}}function R(r){return new v(r)}s.AuthError=c,s.ConfigError=f,s.GenationClient=v,s.GenationError=d,s.LocalStorage=k,s.MemoryStorage=T,s.NetworkError=h,s.SessionStorage=b,s.createClient=R,s.createStorage=_,Object.defineProperty(s,Symbol.toStringTag,{value:"Module"})}));
2
2
  //# sourceMappingURL=genation.umd.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"genation.umd.js","sources":["../src/http/errors.ts","../src/http/client.ts","../src/auth/pkce.ts","../src/auth/token-manager.ts","../src/auth/oauth.ts","../src/storage/memory.ts","../src/storage/local-storage.ts","../src/storage/session-storage.ts","../src/storage/index.ts","../src/utils/converter.ts","../src/client.ts"],"sourcesContent":["/**\r\n * Base error class for Genation SDK\r\n */\r\nexport class GenationError extends Error {\r\n public code: string;\r\n public cause?: unknown;\r\n\r\n constructor(message: string, code: string, cause?: unknown) {\r\n super(message);\r\n this.name = \"GenationError\";\r\n this.code = code;\r\n this.cause = cause;\r\n }\r\n}\r\n\r\n/**\r\n * Authentication-related errors\r\n */\r\nexport class AuthError extends GenationError {\r\n constructor(message: string, code: string, cause?: unknown) {\r\n super(message, code, cause);\r\n this.name = \"AuthError\";\r\n }\r\n\r\n static invalidGrant(\r\n message = \"Invalid authorization code or refresh token\",\r\n ) {\r\n return new AuthError(message, \"invalid_grant\");\r\n }\r\n\r\n static accessDenied(message = \"User denied access\") {\r\n return new AuthError(message, \"access_denied\");\r\n }\r\n\r\n static expiredToken(message = \"Token has expired\") {\r\n return new AuthError(message, \"expired_token\");\r\n }\r\n\r\n static invalidState(message = \"State mismatch, possible CSRF attack\") {\r\n return new AuthError(message, \"invalid_state\");\r\n }\r\n\r\n static pkceVerificationFailed(message = \"PKCE verification failed\") {\r\n return new AuthError(message, \"pkce_verification_failed\");\r\n }\r\n}\r\n\r\n/**\r\n * Network-related errors\r\n */\r\nexport class NetworkError extends GenationError {\r\n public status?: number;\r\n\r\n constructor(message: string, status?: number, cause?: unknown) {\r\n super(message, \"network_error\", cause);\r\n this.name = \"NetworkError\";\r\n this.status = status;\r\n }\r\n\r\n static fromResponse(response: Response) {\r\n return new NetworkError(\r\n `HTTP ${response.status}: ${response.statusText}`,\r\n response.status,\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Configuration-related errors\r\n */\r\nexport class ConfigError extends GenationError {\r\n constructor(message: string) {\r\n super(message, \"config_error\");\r\n this.name = \"ConfigError\";\r\n }\r\n\r\n static missingField(field: string) {\r\n return new ConfigError(`Missing required config field: ${field}`);\r\n }\r\n}\r\n","import { NetworkError } from \"./errors\";\r\n\r\nexport interface HttpClientConfig {\r\n baseUrl: string;\r\n timeout?: number;\r\n}\r\n\r\nexport interface RequestOptions {\r\n method?: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\";\r\n headers?: Record<string, string>;\r\n body?: unknown;\r\n params?: Record<string, string>;\r\n}\r\n\r\n/**\r\n * Simple HTTP client wrapper around fetch\r\n */\r\nexport class HttpClient {\r\n private baseUrl: string;\r\n private timeout: number;\r\n\r\n constructor(config: HttpClientConfig) {\r\n this.baseUrl = config.baseUrl.replace(/\\/$/, \"\");\r\n this.timeout = config.timeout ?? 30000;\r\n }\r\n\r\n /**\r\n * Make an HTTP request\r\n */\r\n async request<T>(\r\n endpoint: string,\r\n options: RequestOptions = {},\r\n ): Promise<T> {\r\n const { method = \"GET\", headers = {}, body, params } = options;\r\n\r\n // Build URL with query params\r\n let url = `${this.baseUrl}${endpoint}`;\r\n if (params) {\r\n const searchParams = new URLSearchParams(params);\r\n url += `?${searchParams.toString()}`;\r\n }\r\n\r\n // Setup abort controller for timeout\r\n const controller = new AbortController();\r\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\r\n\r\n try {\r\n const response = await fetch(url, {\r\n method,\r\n headers: {\r\n \"Content-Type\": \"application/json\",\r\n ...headers,\r\n },\r\n body: body ? JSON.stringify(body) : undefined,\r\n signal: controller.signal,\r\n });\r\n\r\n clearTimeout(timeoutId);\r\n\r\n if (!response.ok) {\r\n throw NetworkError.fromResponse(response);\r\n }\r\n\r\n return await response.json();\r\n } catch (error) {\r\n clearTimeout(timeoutId);\r\n\r\n if (error instanceof NetworkError) {\r\n throw error;\r\n }\r\n\r\n if (error instanceof Error && error.name === \"AbortError\") {\r\n throw new NetworkError(\"Request timeout\", undefined, error);\r\n }\r\n\r\n throw new NetworkError(\"Network request failed\", undefined, error);\r\n }\r\n }\r\n\r\n /**\r\n * POST request with form data (for OAuth token exchange)\r\n */\r\n async postForm<T>(\r\n endpoint: string,\r\n data: Record<string, string>,\r\n headers: Record<string, string> = {},\r\n ): Promise<T> {\r\n const url = `${this.baseUrl}${endpoint}`;\r\n const controller = new AbortController();\r\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\r\n\r\n try {\r\n const response = await fetch(url, {\r\n method: \"POST\",\r\n headers: {\r\n \"Content-Type\": \"application/x-www-form-urlencoded\",\r\n ...headers,\r\n },\r\n body: new URLSearchParams(data).toString(),\r\n signal: controller.signal,\r\n });\r\n\r\n clearTimeout(timeoutId);\r\n\r\n if (!response.ok) {\r\n throw NetworkError.fromResponse(response);\r\n }\r\n\r\n return await response.json();\r\n } catch (error) {\r\n clearTimeout(timeoutId);\r\n\r\n if (error instanceof NetworkError) {\r\n throw error;\r\n }\r\n\r\n throw new NetworkError(\"Network request failed\", undefined, error);\r\n }\r\n }\r\n}\r\n\r\nexport { AuthError, ConfigError, GenationError, NetworkError } from \"./errors\";\r\n","import type { PKCEChallenge } from \"../types\";\r\n\r\n/**\r\n * Base64URL encode a buffer (matches Supabase implementation)\r\n */\r\nfunction base64URLEncode(buffer: Uint8Array): string {\r\n return btoa(String.fromCharCode(...buffer))\r\n .replace(/\\+/g, \"-\")\r\n .replace(/\\//g, \"_\")\r\n .replace(/=/g, \"\");\r\n}\r\n\r\n/**\r\n * Generate a random code verifier (43-128 characters)\r\n * Matches Supabase implementation\r\n */\r\nfunction generateCodeVerifier(): string {\r\n const array = new Uint8Array(32);\r\n crypto.getRandomValues(array);\r\n return base64URLEncode(array);\r\n}\r\n\r\n/**\r\n * Create code challenge from verifier using SHA-256\r\n * Matches Supabase implementation\r\n */\r\nasync function generateCodeChallenge(verifier: string): Promise<string> {\r\n const encoder = new TextEncoder();\r\n const data = encoder.encode(verifier);\r\n const hash = await crypto.subtle.digest(\"SHA-256\", data);\r\n return base64URLEncode(new Uint8Array(hash));\r\n}\r\n\r\n/**\r\n * Generate PKCE code verifier and challenge pair\r\n * Uses S256 method as required by OAuth 2.1\r\n */\r\nexport async function generatePKCE(): Promise<PKCEChallenge> {\r\n const codeVerifier = generateCodeVerifier();\r\n const codeChallenge = await generateCodeChallenge(codeVerifier);\r\n\r\n return {\r\n codeVerifier,\r\n codeChallenge,\r\n codeChallengeMethod: \"S256\",\r\n };\r\n}\r\n\r\n/**\r\n * Generate random state parameter for CSRF protection\r\n */\r\nexport function generateState(): string {\r\n const array = new Uint8Array(16);\r\n crypto.getRandomValues(array);\r\n return base64URLEncode(array);\r\n}\r\n","import type { TokenSet, TokenStorage } from \"../types\";\r\n\r\nconst TOKEN_KEY = \"tokens\";\r\nconst PKCE_KEY = \"pkce\";\r\nconst STATE_KEY = \"state\";\r\n\r\n/**\r\n * Manages token lifecycle: storage, retrieval, refresh\r\n */\r\nexport class TokenManager {\r\n private storage: TokenStorage;\r\n\r\n constructor(storage: TokenStorage) {\r\n this.storage = storage;\r\n }\r\n\r\n /**\r\n * Store token set\r\n */\r\n async setTokens(tokens: TokenSet): Promise<void> {\r\n await this.storage.set(TOKEN_KEY, JSON.stringify(tokens));\r\n }\r\n\r\n /**\r\n * Get stored tokens\r\n */\r\n async getTokens(): Promise<TokenSet | null> {\r\n const data = await this.storage.get(TOKEN_KEY);\r\n if (!data) return null;\r\n\r\n try {\r\n return JSON.parse(data) as TokenSet;\r\n } catch {\r\n return null;\r\n }\r\n }\r\n\r\n /**\r\n * Clear stored tokens\r\n */\r\n async clearTokens(): Promise<void> {\r\n await this.storage.remove(TOKEN_KEY);\r\n }\r\n\r\n /**\r\n * Check if access token is expired\r\n */\r\n async isTokenExpired(): Promise<boolean> {\r\n const tokens = await this.getTokens();\r\n if (!tokens) return true;\r\n\r\n const expiresAt = tokens.issuedAt + tokens.expiresIn * 1000;\r\n // Consider expired if less than 60 seconds remaining\r\n return Date.now() > expiresAt - 60000;\r\n }\r\n\r\n /**\r\n * Store PKCE verifier for later validation\r\n */\r\n async setPKCE(codeVerifier: string): Promise<void> {\r\n await this.storage.set(PKCE_KEY, codeVerifier);\r\n }\r\n\r\n /**\r\n * Get and clear stored PKCE verifier\r\n */\r\n async consumePKCE(): Promise<string | null> {\r\n const verifier = await this.storage.get(PKCE_KEY);\r\n if (verifier) {\r\n await this.storage.remove(PKCE_KEY);\r\n }\r\n return verifier;\r\n }\r\n\r\n /**\r\n * Store state for CSRF validation\r\n */\r\n async setState(state: string): Promise<void> {\r\n await this.storage.set(STATE_KEY, state);\r\n }\r\n\r\n /**\r\n * Get and clear stored state\r\n */\r\n async consumeState(): Promise<string | null> {\r\n const state = await this.storage.get(STATE_KEY);\r\n if (state) {\r\n await this.storage.remove(STATE_KEY);\r\n }\r\n return state;\r\n }\r\n\r\n /**\r\n * Clear all auth-related data\r\n */\r\n async clearAll(): Promise<void> {\r\n await this.storage.clear();\r\n }\r\n}\r\n","import type { GenationConfig, TokenSet } from \"../types\";\r\nimport { AuthError, HttpClient } from \"../http\";\r\nimport { generatePKCE, generateState } from \"./pkce\";\r\nimport { TokenManager } from \"./token-manager\";\r\n\r\nconst DEFAULT_AUTH_URL = \"https://mnnoheowoowbtpuoguul.supabase.co/auth/v1\";\r\n\r\ninterface TokenResponse {\r\n access_token: string;\r\n refresh_token?: string;\r\n token_type: string;\r\n expires_in: number;\r\n scope?: string;\r\n}\r\n\r\n/**\r\n * OAuth 2.1 handler with PKCE support\r\n */\r\nexport class OAuth2Handler {\r\n private config:\r\n & Required<\r\n Pick<GenationConfig, \"clientId\" | \"clientSecret\" | \"redirectUri\">\r\n >\r\n & Pick<GenationConfig, \"scopes\" | \"authUrl\">;\r\n private http: HttpClient;\r\n private tokenManager: TokenManager;\r\n\r\n constructor(\r\n config: GenationConfig,\r\n tokenManager: TokenManager,\r\n ) {\r\n this.config = {\r\n clientId: config.clientId,\r\n clientSecret: config.clientSecret,\r\n redirectUri: config.redirectUri,\r\n scopes: config.scopes,\r\n authUrl: config.authUrl ?? DEFAULT_AUTH_URL,\r\n };\r\n this.http = new HttpClient({ baseUrl: this.config.authUrl! });\r\n this.tokenManager = tokenManager;\r\n }\r\n\r\n /**\r\n * Generate authorization URL for OAuth flow\r\n * Stores PKCE verifier and state for later validation\r\n */\r\n async getAuthorizationUrl(): Promise<string> {\r\n const pkce = await generatePKCE();\r\n const state = generateState();\r\n\r\n // Store for later validation\r\n await this.tokenManager.setPKCE(pkce.codeVerifier);\r\n await this.tokenManager.setState(state);\r\n\r\n const params = new URLSearchParams({\r\n response_type: \"code\",\r\n client_id: this.config.clientId,\r\n redirect_uri: this.config.redirectUri,\r\n state,\r\n code_challenge: pkce.codeChallenge,\r\n code_challenge_method: pkce.codeChallengeMethod,\r\n });\r\n\r\n if (this.config.scopes && this.config.scopes.length > 0) {\r\n params.append(\"scope\", this.config.scopes.join(\" \"));\r\n }\r\n\r\n return `${this.config.authUrl}/oauth/authorize?${params.toString()}`;\r\n }\r\n\r\n /**\r\n * Exchange authorization code for tokens\r\n */\r\n async exchangeCode(code: string, state: string): Promise<TokenSet> {\r\n // Validate state\r\n const storedState = await this.tokenManager.consumeState();\r\n if (!storedState || storedState !== state) {\r\n throw AuthError.invalidState();\r\n }\r\n\r\n // Get PKCE verifier\r\n const codeVerifier = await this.tokenManager.consumePKCE();\r\n if (!codeVerifier) {\r\n throw AuthError.pkceVerificationFailed(\"Missing code verifier\");\r\n }\r\n\r\n // Exchange code for tokens\r\n const response = await this.http.postForm<TokenResponse>(\r\n \"/oauth/token\",\r\n {\r\n grant_type: \"authorization_code\",\r\n code,\r\n redirect_uri: this.config.redirectUri,\r\n client_id: this.config.clientId,\r\n client_secret: this.config.clientSecret,\r\n code_verifier: codeVerifier,\r\n },\r\n );\r\n\r\n const tokens = this.mapTokenResponse(response);\r\n await this.tokenManager.setTokens(tokens);\r\n\r\n return tokens;\r\n }\r\n\r\n /**\r\n * Refresh access token using refresh token\r\n */\r\n async refreshToken(): Promise<TokenSet> {\r\n const currentTokens = await this.tokenManager.getTokens();\r\n if (!currentTokens?.refreshToken) {\r\n throw AuthError.invalidGrant(\"No refresh token available\");\r\n }\r\n\r\n const response = await this.http.postForm<TokenResponse>(\r\n \"/oauth/token\",\r\n {\r\n grant_type: \"refresh_token\",\r\n refresh_token: currentTokens.refreshToken,\r\n client_id: this.config.clientId,\r\n client_secret: this.config.clientSecret,\r\n },\r\n );\r\n\r\n const tokens = this.mapTokenResponse(response);\r\n await this.tokenManager.setTokens(tokens);\r\n\r\n return tokens;\r\n }\r\n\r\n /**\r\n * Revoke current tokens\r\n */\r\n async revokeToken(): Promise<void> {\r\n const tokens = await this.tokenManager.getTokens();\r\n if (!tokens) return;\r\n\r\n try {\r\n await this.http.postForm(\"/oauth/revoke\", {\r\n token: tokens.accessToken,\r\n client_id: this.config.clientId,\r\n client_secret: this.config.clientSecret,\r\n });\r\n } finally {\r\n await this.tokenManager.clearTokens();\r\n }\r\n }\r\n\r\n /**\r\n * Map OAuth token response to TokenSet\r\n */\r\n private mapTokenResponse(response: TokenResponse): TokenSet {\r\n return {\r\n accessToken: response.access_token,\r\n refreshToken: response.refresh_token,\r\n tokenType: response.token_type,\r\n expiresIn: response.expires_in,\r\n issuedAt: Date.now(),\r\n scope: response.scope,\r\n };\r\n }\r\n}\r\n","import type { TokenStorage } from \"../types\";\r\n\r\n/**\r\n * In-memory storage implementation\r\n * Tokens are lost when page refreshes\r\n */\r\nexport class MemoryStorage implements TokenStorage {\r\n private store = new Map<string, string>();\r\n\r\n async get(key: string): Promise<string | null> {\r\n return this.store.get(key) ?? null;\r\n }\r\n\r\n async set(key: string, value: string): Promise<void> {\r\n this.store.set(key, value);\r\n }\r\n\r\n async remove(key: string): Promise<void> {\r\n this.store.delete(key);\r\n }\r\n\r\n async clear(): Promise<void> {\r\n this.store.clear();\r\n }\r\n}\r\n","import type { TokenStorage } from \"../types\";\r\n\r\n/**\r\n * Browser localStorage implementation\r\n * Tokens persist across browser sessions\r\n */\r\nexport class LocalStorage implements TokenStorage {\r\n private prefix: string;\r\n\r\n constructor(prefix = \"genation\") {\r\n this.prefix = prefix;\r\n }\r\n\r\n private getKey(key: string): string {\r\n return `${this.prefix}:${key}`;\r\n }\r\n\r\n async get(key: string): Promise<string | null> {\r\n if (typeof window === \"undefined\") return null;\r\n return localStorage.getItem(this.getKey(key));\r\n }\r\n\r\n async set(key: string, value: string): Promise<void> {\r\n if (typeof window === \"undefined\") return;\r\n localStorage.setItem(this.getKey(key), value);\r\n }\r\n\r\n async remove(key: string): Promise<void> {\r\n if (typeof window === \"undefined\") return;\r\n localStorage.removeItem(this.getKey(key));\r\n }\r\n\r\n async clear(): Promise<void> {\r\n if (typeof window === \"undefined\") return;\r\n const keys = Object.keys(localStorage).filter((k) =>\r\n k.startsWith(`${this.prefix}:`)\r\n );\r\n keys.forEach((k) => localStorage.removeItem(k));\r\n }\r\n}\r\n","import type { TokenStorage } from \"../types\";\r\n\r\n/**\r\n * Browser sessionStorage implementation\r\n * Tokens persist until browser tab is closed\r\n */\r\nexport class SessionStorage implements TokenStorage {\r\n private prefix: string;\r\n\r\n constructor(prefix = \"genation\") {\r\n this.prefix = prefix;\r\n }\r\n\r\n private getKey(key: string): string {\r\n return `${this.prefix}:${key}`;\r\n }\r\n\r\n async get(key: string): Promise<string | null> {\r\n if (typeof window === \"undefined\") return null;\r\n return sessionStorage.getItem(this.getKey(key));\r\n }\r\n\r\n async set(key: string, value: string): Promise<void> {\r\n if (typeof window === \"undefined\") return;\r\n sessionStorage.setItem(this.getKey(key), value);\r\n }\r\n\r\n async remove(key: string): Promise<void> {\r\n if (typeof window === \"undefined\") return;\r\n sessionStorage.removeItem(this.getKey(key));\r\n }\r\n\r\n async clear(): Promise<void> {\r\n if (typeof window === \"undefined\") return;\r\n const keys = Object.keys(sessionStorage).filter((k) =>\r\n k.startsWith(`${this.prefix}:`)\r\n );\r\n keys.forEach((k) => sessionStorage.removeItem(k));\r\n }\r\n}\r\n","/**\r\n * @fileoverview Storage factory and implementations\r\n * @module storage\r\n */\r\n\r\nimport type { StorageType, TokenStorage } from \"../types\";\r\nimport { MemoryStorage } from \"./memory\";\r\nimport { LocalStorage } from \"./local-storage\";\r\nimport { SessionStorage } from \"./session-storage\";\r\n\r\nexport { MemoryStorage } from \"./memory\";\r\nexport { LocalStorage } from \"./local-storage\";\r\nexport { SessionStorage } from \"./session-storage\";\r\n\r\n/**\r\n * Create a storage instance based on type\r\n *\r\n * @param type - Storage type to create\r\n * @returns Storage implementation\r\n *\r\n * @example\r\n * ```typescript\r\n * const storage = createStorage('localStorage');\r\n * await storage.set('key', 'value');\r\n * ```\r\n */\r\nexport function createStorage(\r\n type: StorageType = \"localStorage\",\r\n): TokenStorage {\r\n switch (type) {\r\n case \"memory\":\r\n return new MemoryStorage();\r\n case \"localStorage\":\r\n return new LocalStorage();\r\n case \"sessionStorage\":\r\n return new SessionStorage();\r\n default:\r\n return new LocalStorage();\r\n }\r\n}\r\n","// Function to convert snake_case to camelCase, handles arrays and objects recursively\r\nexport function snakeToCamel(data: any): any {\r\n if (Array.isArray(data)) {\r\n return data.map(snakeToCamel);\r\n } else if (typeof data === \"object\" && data !== null) {\r\n return Object.fromEntries(\r\n Object.entries(data).map(([key, value]) => [\r\n key.replace(/_([a-z])/g, (_, c) => c.toUpperCase()),\r\n snakeToCamel(value)\r\n ])\r\n );\r\n }\r\n return data;\r\n}","/**\r\n * @fileoverview Main Genation SDK client\r\n * @module client\r\n */\r\n\r\nimport type {\r\n AuthEvent,\r\n AuthStateChangeCallback,\r\n GenationConfig,\r\n Session,\r\n Subscription,\r\n TokenSet,\r\n TokenStorage,\r\n User,\r\n} from \"./types\";\r\nimport { OAuth2Handler, TokenManager } from \"./auth\";\r\nimport { createStorage } from \"./storage\";\r\nimport { ConfigError, HttpClient } from \"./http\";\r\nimport type { License, LicenseResponse } from \"./types/server/license\";\r\nimport type { ApiResponse } from \"./types/server/api-response\";\r\nimport { snakeToCamel } from \"./utils/converter\";\r\n\r\n// Re-export types for convenience\r\nexport type { AuthEvent, AuthStateChangeCallback, Session, Subscription };\r\n\r\n/**\r\n * Main Genation SDK client\r\n *\r\n * OAuth 2.1 authentication client for Genation platform.\r\n * Supports PKCE flow and automatic token refresh.\r\n *\r\n * @example\r\n * ```typescript\r\n * import { createClient } from 'genation';\r\n *\r\n * const client = createClient({\r\n * clientId: 'your-client-id',\r\n * clientSecret: 'your-client-secret',\r\n * redirectUri: 'http://localhost:3000/callback'\r\n * });\r\n *\r\n * // Listen to auth state changes\r\n * const { subscription } = client.onAuthStateChange((event, session) => {\r\n * if (event === 'SIGNED_IN') {\r\n * console.log('User signed in:', session?.user);\r\n * }\r\n * });\r\n *\r\n * // Start login flow\r\n * window.location.href = await client.signIn();\r\n * ```\r\n */\r\nexport class GenationClient {\r\n private oauth: OAuth2Handler;\r\n private tokenManager: TokenManager;\r\n private http: HttpClient;\r\n private httpServer: HttpClient;\r\n private listeners: Set<AuthStateChangeCallback> = new Set();\r\n private initialized = false;\r\n\r\n constructor(config: GenationConfig) {\r\n this.validateConfig(config);\r\n\r\n const storage: TokenStorage = typeof config.storage === \"object\"\r\n ? (config.storage as unknown as TokenStorage)\r\n : createStorage(config.storage);\r\n\r\n this.tokenManager = new TokenManager(storage);\r\n this.oauth = new OAuth2Handler(config, this.tokenManager);\r\n this.http = new HttpClient({\r\n baseUrl: config.authUrl ??\r\n \"https://mnnoheowoowbtpuoguul.supabase.co/auth/v1\",\r\n });\r\n this.httpServer = new HttpClient({\r\n baseUrl: \"https://ff-api.genation.ai/api/v2/client\"\r\n });\r\n }\r\n\r\n private validateConfig(config: GenationConfig): void {\r\n if (!config.clientId) throw ConfigError.missingField(\"clientId\");\r\n if (!config.clientSecret) {\r\n throw ConfigError.missingField(\"clientSecret\");\r\n }\r\n if (!config.redirectUri) throw ConfigError.missingField(\"redirectUri\");\r\n }\r\n\r\n /**\r\n * Emit auth state change event to all listeners\r\n */\r\n private async emitAuthStateChange(event: AuthEvent): Promise<void> {\r\n const session = await this.getSession();\r\n this.listeners.forEach((callback) => {\r\n try {\r\n callback(event, session);\r\n } catch (error) {\r\n console.error(\"Error in auth state change callback:\", error);\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Listen to authentication state changes\r\n *\r\n * Register a callback that fires when:\r\n * - `INITIAL_SESSION`: On first subscription, with current session state\r\n * - `SIGNED_IN`: User successfully authenticated\r\n * - `SIGNED_OUT`: User logged out or session expired\r\n * - `TOKEN_REFRESHED`: Access token was automatically refreshed\r\n *\r\n * @param callback - Function called on each auth state change\r\n * @returns Object containing subscription with `unsubscribe()` method\r\n *\r\n * @example\r\n * ```typescript\r\n * const { subscription } = client.onAuthStateChange((event, session) => {\r\n * console.log('Auth event:', event);\r\n *\r\n * if (event === 'INITIAL_SESSION') {\r\n * // Check if user was previously logged in\r\n * if (session) {\r\n * console.log('Welcome back!', session.user);\r\n * }\r\n * } else if (event === 'SIGNED_IN') {\r\n * // User just signed in\r\n * console.log('Signed in:', session?.user);\r\n * } else if (event === 'SIGNED_OUT') {\r\n * // Clear app state, redirect to login\r\n * console.log('Signed out');\r\n * }\r\n * });\r\n *\r\n * // Cleanup when component unmounts\r\n * subscription.unsubscribe();\r\n * ```\r\n */\r\n onAuthStateChange(\r\n callback: AuthStateChangeCallback,\r\n ): { subscription: Subscription } {\r\n this.listeners.add(callback);\r\n\r\n // Emit INITIAL_SESSION on first subscription\r\n if (!this.initialized) {\r\n this.initialized = true;\r\n setTimeout(() => {\r\n this.emitAuthStateChange(\"INITIAL_SESSION\");\r\n }, 0);\r\n } else {\r\n // For subsequent subscriptions, also emit current state\r\n setTimeout(() => {\r\n this.emitAuthStateChange(\"INITIAL_SESSION\");\r\n }, 0);\r\n }\r\n\r\n return {\r\n subscription: {\r\n unsubscribe: () => {\r\n this.listeners.delete(callback);\r\n },\r\n },\r\n };\r\n }\r\n\r\n /**\r\n * Start OAuth sign-in flow\r\n *\r\n * Generates authorization URL with PKCE challenge.\r\n * Redirect user to this URL to start authentication.\r\n *\r\n * @returns Authorization URL to redirect user to\r\n *\r\n * @example\r\n * ```typescript\r\n * async function handleLogin() {\r\n * const url = await client.signIn();\r\n * window.location.href = url;\r\n * }\r\n * ```\r\n */\r\n async signIn(): Promise<string> {\r\n return this.oauth.getAuthorizationUrl();\r\n }\r\n\r\n /**\r\n * Handle OAuth callback after user authentication\r\n *\r\n * Call this on your redirect URI page to exchange\r\n * the authorization code for access tokens.\r\n * Triggers `SIGNED_IN` event on success.\r\n *\r\n * @param code - Authorization code from URL query params\r\n * @param state - State parameter for CSRF validation\r\n * @returns Token set with access and refresh tokens\r\n * @throws {AuthError} If state mismatch or code exchange fails\r\n *\r\n * @example\r\n * ```typescript\r\n * // On your /callback page\r\n * async function handleCallback() {\r\n * const params = new URLSearchParams(window.location.search);\r\n * const code = params.get('code');\r\n * const state = params.get('state');\r\n *\r\n * if (code && state) {\r\n * await client.handleCallback(code, state);\r\n * // onAuthStateChange will fire with SIGNED_IN event\r\n * }\r\n * }\r\n * ```\r\n */\r\n async handleCallback(code: string, state: string): Promise<TokenSet> {\r\n const tokens = await this.oauth.exchangeCode(code, state);\r\n\r\n // Debug: Fetch user immediately to check if it works\r\n try {\r\n const user = await this.fetchUser(tokens.accessToken);\r\n console.log(\"Debug: handleCallback fetched user:\", user);\r\n } catch (e) {\r\n console.error(\"Debug: handleCallback fetchUser failed:\", e);\r\n }\r\n\r\n await this.emitAuthStateChange(\"SIGNED_IN\");\r\n return tokens;\r\n }\r\n\r\n // /**\r\n // * Sign out and revoke tokens\r\n // *\r\n // * Clears local session and revokes tokens on server.\r\n // * Triggers `SIGNED_OUT` event for all listeners.\r\n // *\r\n // * @example\r\n // * ```typescript\r\n // * async function handleLogout() {\r\n // * await client.signOut();\r\n // * // onAuthStateChange will fire with SIGNED_OUT event\r\n // * }\r\n // * ```\r\n // */\r\n // async signOut(): Promise<void> {\r\n // await this.oauth.revokeToken();\r\n // await this.emitAuthStateChange(\"SIGNED_OUT\");\r\n // }\r\n\r\n /**\r\n * Get current session\r\n *\r\n * Returns session with access token and user info.\r\n * Automatically refreshes token if expired.\r\n *\r\n * @returns Current session or null if not authenticated\r\n *\r\n * @example\r\n * ```typescript\r\n * const session = await client.getSession();\r\n * if (session) {\r\n * console.log('Logged in as:', session.user?.email);\r\n *\r\n * // Use access token for API calls\r\n * fetch('/api/data', {\r\n * headers: { Authorization: `Bearer ${session.accessToken}` }\r\n * });\r\n * }\r\n * ```\r\n */\r\n async getSession(): Promise<Session | null> {\r\n const isExpired = await this.tokenManager.isTokenExpired();\r\n\r\n if (isExpired) {\r\n try {\r\n await this.oauth.refreshToken();\r\n } catch {\r\n return null;\r\n }\r\n }\r\n\r\n const tokens = await this.tokenManager.getTokens();\r\n if (!tokens) return null;\r\n\r\n const user = await this.fetchUser(tokens.accessToken);\r\n\r\n return {\r\n accessToken: tokens.accessToken,\r\n refreshToken: tokens.refreshToken,\r\n expiresIn: tokens.expiresIn,\r\n expiresAt: tokens.issuedAt + tokens.expiresIn * 1000,\r\n user,\r\n };\r\n }\r\n /**\r\n * Get licenses\r\n * @param accessToken - The access token to use for the request\r\n * @param options - The options for the request\r\n * @param options.expiresAfter - Query licenses that are expired after the given date, default set to today to get all valid licenses (unexpired licenses)\r\n * @returns The licenses\r\n */\r\n async getLicenses(options: { expiresAfter?: Date } = {}): Promise<License[] | null> {\r\n const session = await this.getSession();\r\n if (!session) {\r\n return null;\r\n }\r\n const accessToken = session.accessToken;\r\n const { expiresAfter = new Date() } = options;\r\n const response = await this.httpServer.request<ApiResponse<LicenseResponse[]>>(\"/licenses\", {\r\n headers: { Authorization: `Bearer ${accessToken}` },\r\n params: { expiresAfter: expiresAfter.toISOString() }\r\n });\r\n if (!response.ok) {\r\n console.error(\"GenationClient: Error fetching licenses:\", response.error);\r\n return null;\r\n }\r\n console.log(\"GenationClient: Response data:\", response.data);\r\n const licenses: License[] = snakeToCamel(response.data);\r\n console.log(\"GenationClient: Licenses:\", licenses);\r\n return licenses;\r\n }\r\n /**\r\n * Fetch user info from auth server\r\n */\r\n private async fetchUser(accessToken: string): Promise<User | null> {\r\n try {\r\n // Use standard OIDC UserInfo endpoint\r\n // https://supabase.com/docs/guides/auth/oauth-server/oauth-flows#userinfo-endpoint\r\n const response = await this.http.request<{\r\n sub: string;\r\n email?: string;\r\n name?: string;\r\n picture?: string;\r\n email_verified?: boolean;\r\n phone_number?: string;\r\n phone_number_verified?: boolean;\r\n }>(\"/oauth/userinfo\", {\r\n headers: { Authorization: `Bearer ${accessToken}` },\r\n });\r\n\r\n return {\r\n sub: response.sub,\r\n name: response.name,\r\n picture: response.picture,\r\n email: response.email,\r\n email_verified: response.email_verified,\r\n phone_number: response.phone_number,\r\n phone_number_verified: response.phone_number_verified,\r\n };\r\n } catch (error) {\r\n console.error(\"GenationClient: Error fetching user:\", error);\r\n return null;\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Create a new Genation client instance\r\n *\r\n * Factory function for creating SDK client with configuration.\r\n *\r\n * @param config - Client configuration options\r\n * @returns Configured GenationClient instance\r\n *\r\n * @example\r\n * ```typescript\r\n * import { createClient } from 'genation';\r\n *\r\n * const client = createClient({\r\n * clientId: 'your-client-id',\r\n * clientSecret: 'your-client-secret',\r\n * redirectUri: 'http://localhost:3000/callback',\r\n * // Optional\r\n * scopes: ['openid', 'profile', 'email'],\r\n * storage: 'localStorage',\r\n * });\r\n * ```\r\n */\r\nexport function createClient(config: GenationConfig): GenationClient {\r\n return new GenationClient(config);\r\n}\r\n"],"names":["GenationError","message","code","cause","AuthError","NetworkError","status","response","ConfigError","field","HttpClient","config","endpoint","options","method","headers","body","params","url","searchParams","controller","timeoutId","error","data","base64URLEncode","buffer","generateCodeVerifier","array","generateCodeChallenge","verifier","hash","generatePKCE","codeVerifier","codeChallenge","generateState","TOKEN_KEY","PKCE_KEY","STATE_KEY","TokenManager","storage","tokens","expiresAt","state","DEFAULT_AUTH_URL","OAuth2Handler","tokenManager","pkce","storedState","currentTokens","MemoryStorage","key","value","LocalStorage","prefix","k","SessionStorage","createStorage","type","snakeToCamel","_","c","GenationClient","event","session","callback","user","e","accessToken","expiresAfter","licenses","createClient"],"mappings":"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"}
1
+ {"version":3,"file":"genation.umd.js","sources":["../src/http/errors.ts","../src/http/client.ts","../src/auth/pkce.ts","../src/auth/token-manager.ts","../src/auth/oauth.ts","../src/storage/memory.ts","../src/storage/local-storage.ts","../src/storage/session-storage.ts","../src/storage/index.ts","../src/utils/converter.ts","../src/client.ts"],"sourcesContent":["/**\r\n * Base error class for Genation SDK\r\n */\r\nexport class GenationError extends Error {\r\n public code: string;\r\n public cause?: unknown;\r\n\r\n constructor(message: string, code: string, cause?: unknown) {\r\n super(message);\r\n this.name = \"GenationError\";\r\n this.code = code;\r\n this.cause = cause;\r\n }\r\n}\r\n\r\n/**\r\n * Authentication-related errors\r\n */\r\nexport class AuthError extends GenationError {\r\n constructor(message: string, code: string, cause?: unknown) {\r\n super(message, code, cause);\r\n this.name = \"AuthError\";\r\n }\r\n\r\n static invalidGrant(\r\n message = \"Invalid authorization code or refresh token\",\r\n ) {\r\n return new AuthError(message, \"invalid_grant\");\r\n }\r\n\r\n static accessDenied(message = \"User denied access\") {\r\n return new AuthError(message, \"access_denied\");\r\n }\r\n\r\n static expiredToken(message = \"Token has expired\") {\r\n return new AuthError(message, \"expired_token\");\r\n }\r\n\r\n static invalidState(message = \"State mismatch, possible CSRF attack\") {\r\n return new AuthError(message, \"invalid_state\");\r\n }\r\n\r\n static pkceVerificationFailed(message = \"PKCE verification failed\") {\r\n return new AuthError(message, \"pkce_verification_failed\");\r\n }\r\n}\r\n\r\n/**\r\n * Network-related errors\r\n */\r\nexport class NetworkError extends GenationError {\r\n public status?: number;\r\n\r\n constructor(message: string, status?: number, cause?: unknown) {\r\n super(message, \"network_error\", cause);\r\n this.name = \"NetworkError\";\r\n this.status = status;\r\n }\r\n\r\n static fromResponse(response: Response) {\r\n return new NetworkError(\r\n `HTTP ${response.status}: ${response.statusText}`,\r\n response.status,\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Configuration-related errors\r\n */\r\nexport class ConfigError extends GenationError {\r\n constructor(message: string) {\r\n super(message, \"config_error\");\r\n this.name = \"ConfigError\";\r\n }\r\n\r\n static missingField(field: string) {\r\n return new ConfigError(`Missing required config field: ${field}`);\r\n }\r\n}\r\n","import { NetworkError } from \"./errors\";\r\n\r\nexport interface HttpClientConfig {\r\n baseUrl: string;\r\n timeout?: number;\r\n}\r\n\r\nexport interface RequestOptions {\r\n method?: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\";\r\n headers?: Record<string, string>;\r\n body?: unknown;\r\n params?: Record<string, string>;\r\n}\r\n\r\n/**\r\n * Simple HTTP client wrapper around fetch\r\n */\r\nexport class HttpClient {\r\n private baseUrl: string;\r\n private timeout: number;\r\n\r\n constructor(config: HttpClientConfig) {\r\n this.baseUrl = config.baseUrl.replace(/\\/$/, \"\");\r\n this.timeout = config.timeout ?? 30000;\r\n }\r\n\r\n /**\r\n * Make an HTTP request\r\n */\r\n async request<T>(\r\n endpoint: string,\r\n options: RequestOptions = {},\r\n ): Promise<T> {\r\n const { method = \"GET\", headers = {}, body, params } = options;\r\n\r\n // Build URL with query params\r\n let url = `${this.baseUrl}${endpoint}`;\r\n if (params) {\r\n const searchParams = new URLSearchParams(params);\r\n url += `?${searchParams.toString()}`;\r\n }\r\n\r\n // Setup abort controller for timeout\r\n const controller = new AbortController();\r\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\r\n\r\n try {\r\n const response = await fetch(url, {\r\n method,\r\n headers: {\r\n \"Content-Type\": \"application/json\",\r\n ...headers,\r\n },\r\n body: body ? JSON.stringify(body) : undefined,\r\n signal: controller.signal,\r\n });\r\n\r\n clearTimeout(timeoutId);\r\n\r\n if (!response.ok) {\r\n throw NetworkError.fromResponse(response);\r\n }\r\n\r\n return await response.json();\r\n } catch (error) {\r\n clearTimeout(timeoutId);\r\n\r\n if (error instanceof NetworkError) {\r\n throw error;\r\n }\r\n\r\n if (error instanceof Error && error.name === \"AbortError\") {\r\n throw new NetworkError(\"Request timeout\", undefined, error);\r\n }\r\n\r\n throw new NetworkError(\"Network request failed\", undefined, error);\r\n }\r\n }\r\n\r\n /**\r\n * POST request with form data (for OAuth token exchange)\r\n */\r\n async postForm<T>(\r\n endpoint: string,\r\n data: Record<string, string>,\r\n headers: Record<string, string> = {},\r\n ): Promise<T> {\r\n const url = `${this.baseUrl}${endpoint}`;\r\n const controller = new AbortController();\r\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\r\n\r\n try {\r\n const response = await fetch(url, {\r\n method: \"POST\",\r\n headers: {\r\n \"Content-Type\": \"application/x-www-form-urlencoded\",\r\n ...headers,\r\n },\r\n body: new URLSearchParams(data).toString(),\r\n signal: controller.signal,\r\n });\r\n\r\n clearTimeout(timeoutId);\r\n\r\n if (!response.ok) {\r\n throw NetworkError.fromResponse(response);\r\n }\r\n\r\n return await response.json();\r\n } catch (error) {\r\n clearTimeout(timeoutId);\r\n\r\n if (error instanceof NetworkError) {\r\n throw error;\r\n }\r\n\r\n throw new NetworkError(\"Network request failed\", undefined, error);\r\n }\r\n }\r\n}\r\n\r\nexport { AuthError, ConfigError, GenationError, NetworkError } from \"./errors\";\r\n","import type { PKCEChallenge } from \"../types\";\r\n\r\n/**\r\n * Base64URL encode a buffer (matches Supabase implementation)\r\n */\r\nfunction base64URLEncode(buffer: Uint8Array): string {\r\n return btoa(String.fromCharCode(...buffer))\r\n .replace(/\\+/g, \"-\")\r\n .replace(/\\//g, \"_\")\r\n .replace(/=/g, \"\");\r\n}\r\n\r\n/**\r\n * Generate a random code verifier (43-128 characters)\r\n * Matches Supabase implementation\r\n */\r\nfunction generateCodeVerifier(): string {\r\n const array = new Uint8Array(32);\r\n crypto.getRandomValues(array);\r\n return base64URLEncode(array);\r\n}\r\n\r\n/**\r\n * Create code challenge from verifier using SHA-256\r\n * Matches Supabase implementation\r\n */\r\nasync function generateCodeChallenge(verifier: string): Promise<string> {\r\n const encoder = new TextEncoder();\r\n const data = encoder.encode(verifier);\r\n const hash = await crypto.subtle.digest(\"SHA-256\", data);\r\n return base64URLEncode(new Uint8Array(hash));\r\n}\r\n\r\n/**\r\n * Generate PKCE code verifier and challenge pair\r\n * Uses S256 method as required by OAuth 2.1\r\n */\r\nexport async function generatePKCE(): Promise<PKCEChallenge> {\r\n const codeVerifier = generateCodeVerifier();\r\n const codeChallenge = await generateCodeChallenge(codeVerifier);\r\n\r\n return {\r\n codeVerifier,\r\n codeChallenge,\r\n codeChallengeMethod: \"S256\",\r\n };\r\n}\r\n\r\n/**\r\n * Generate random state parameter for CSRF protection\r\n */\r\nexport function generateState(): string {\r\n const array = new Uint8Array(16);\r\n crypto.getRandomValues(array);\r\n return base64URLEncode(array);\r\n}\r\n","import type { TokenSet, TokenStorage } from \"../types\";\r\n\r\nconst TOKEN_KEY = \"tokens\";\r\nconst PKCE_KEY = \"pkce\";\r\nconst STATE_KEY = \"state\";\r\n\r\n/**\r\n * Manages token lifecycle: storage, retrieval, refresh\r\n */\r\nexport class TokenManager {\r\n private storage: TokenStorage;\r\n\r\n constructor(storage: TokenStorage) {\r\n this.storage = storage;\r\n }\r\n\r\n /**\r\n * Store token set\r\n */\r\n async setTokens(tokens: TokenSet): Promise<void> {\r\n await this.storage.set(TOKEN_KEY, JSON.stringify(tokens));\r\n }\r\n\r\n /**\r\n * Get stored tokens\r\n */\r\n async getTokens(): Promise<TokenSet | null> {\r\n const data = await this.storage.get(TOKEN_KEY);\r\n if (!data) return null;\r\n\r\n try {\r\n return JSON.parse(data) as TokenSet;\r\n } catch {\r\n return null;\r\n }\r\n }\r\n\r\n /**\r\n * Clear stored tokens\r\n */\r\n async clearTokens(): Promise<void> {\r\n await this.storage.remove(TOKEN_KEY);\r\n }\r\n\r\n /**\r\n * Check if access token is expired\r\n */\r\n async isTokenExpired(): Promise<boolean> {\r\n const tokens = await this.getTokens();\r\n if (!tokens) return true;\r\n\r\n const expiresAt = tokens.issuedAt + tokens.expiresIn * 1000;\r\n // Consider expired if less than 60 seconds remaining\r\n return Date.now() > expiresAt - 60000;\r\n }\r\n\r\n /**\r\n * Store PKCE verifier for later validation\r\n */\r\n async setPKCE(codeVerifier: string): Promise<void> {\r\n await this.storage.set(PKCE_KEY, codeVerifier);\r\n }\r\n\r\n /**\r\n * Get and clear stored PKCE verifier\r\n */\r\n async consumePKCE(): Promise<string | null> {\r\n const verifier = await this.storage.get(PKCE_KEY);\r\n if (verifier) {\r\n await this.storage.remove(PKCE_KEY);\r\n }\r\n return verifier;\r\n }\r\n\r\n /**\r\n * Store state for CSRF validation\r\n */\r\n async setState(state: string): Promise<void> {\r\n await this.storage.set(STATE_KEY, state);\r\n }\r\n\r\n /**\r\n * Get and clear stored state\r\n */\r\n async consumeState(): Promise<string | null> {\r\n const state = await this.storage.get(STATE_KEY);\r\n if (state) {\r\n await this.storage.remove(STATE_KEY);\r\n }\r\n return state;\r\n }\r\n\r\n /**\r\n * Clear all auth-related data\r\n */\r\n async clearAll(): Promise<void> {\r\n await this.storage.clear();\r\n }\r\n}\r\n","import type { GenationConfig, TokenSet } from \"../types\";\r\nimport { AuthError, HttpClient } from \"../http\";\r\nimport { generatePKCE, generateState } from \"./pkce\";\r\nimport { TokenManager } from \"./token-manager\";\r\n\r\nconst DEFAULT_AUTH_URL = \"https://mnnoheowoowbtpuoguul.supabase.co/auth/v1\";\r\n\r\ninterface TokenResponse {\r\n access_token: string;\r\n refresh_token?: string;\r\n token_type: string;\r\n expires_in: number;\r\n scope?: string;\r\n}\r\n\r\n/**\r\n * OAuth 2.1 handler with PKCE support\r\n */\r\nexport class OAuth2Handler {\r\n private config:\r\n & Required<\r\n Pick<GenationConfig, \"clientId\" | \"clientSecret\" | \"redirectUri\">\r\n >\r\n & Pick<GenationConfig, \"scopes\" | \"authUrl\">;\r\n private http: HttpClient;\r\n private tokenManager: TokenManager;\r\n\r\n constructor(\r\n config: GenationConfig,\r\n tokenManager: TokenManager,\r\n ) {\r\n this.config = {\r\n clientId: config.clientId,\r\n clientSecret: config.clientSecret,\r\n redirectUri: config.redirectUri,\r\n scopes: config.scopes,\r\n authUrl: config.authUrl ?? DEFAULT_AUTH_URL,\r\n };\r\n this.http = new HttpClient({ baseUrl: this.config.authUrl! });\r\n this.tokenManager = tokenManager;\r\n }\r\n\r\n /**\r\n * Generate authorization URL for OAuth flow\r\n * Stores PKCE verifier and state for later validation\r\n */\r\n async getAuthorizationUrl(): Promise<string> {\r\n const pkce = await generatePKCE();\r\n const state = generateState();\r\n\r\n // Store for later validation\r\n await this.tokenManager.setPKCE(pkce.codeVerifier);\r\n await this.tokenManager.setState(state);\r\n\r\n const params = new URLSearchParams({\r\n response_type: \"code\",\r\n client_id: this.config.clientId,\r\n redirect_uri: this.config.redirectUri,\r\n state,\r\n code_challenge: pkce.codeChallenge,\r\n code_challenge_method: pkce.codeChallengeMethod,\r\n });\r\n\r\n if (this.config.scopes && this.config.scopes.length > 0) {\r\n params.append(\"scope\", this.config.scopes.join(\" \"));\r\n }\r\n\r\n return `${this.config.authUrl}/oauth/authorize?${params.toString()}`;\r\n }\r\n\r\n /**\r\n * Exchange authorization code for tokens\r\n */\r\n async exchangeCode(code: string, state: string): Promise<TokenSet> {\r\n // Validate state\r\n const storedState = await this.tokenManager.consumeState();\r\n if (!storedState || storedState !== state) {\r\n throw AuthError.invalidState();\r\n }\r\n\r\n // Get PKCE verifier\r\n const codeVerifier = await this.tokenManager.consumePKCE();\r\n if (!codeVerifier) {\r\n throw AuthError.pkceVerificationFailed(\"Missing code verifier\");\r\n }\r\n\r\n // Exchange code for tokens\r\n const response = await this.http.postForm<TokenResponse>(\r\n \"/oauth/token\",\r\n {\r\n grant_type: \"authorization_code\",\r\n code,\r\n redirect_uri: this.config.redirectUri,\r\n client_id: this.config.clientId,\r\n client_secret: this.config.clientSecret,\r\n code_verifier: codeVerifier,\r\n },\r\n );\r\n\r\n const tokens = this.mapTokenResponse(response);\r\n await this.tokenManager.setTokens(tokens);\r\n\r\n return tokens;\r\n }\r\n\r\n /**\r\n * Refresh access token using refresh token\r\n */\r\n async refreshToken(): Promise<TokenSet> {\r\n const currentTokens = await this.tokenManager.getTokens();\r\n if (!currentTokens?.refreshToken) {\r\n throw AuthError.invalidGrant(\"No refresh token available\");\r\n }\r\n\r\n const response = await this.http.postForm<TokenResponse>(\r\n \"/oauth/token\",\r\n {\r\n grant_type: \"refresh_token\",\r\n refresh_token: currentTokens.refreshToken,\r\n client_id: this.config.clientId,\r\n client_secret: this.config.clientSecret,\r\n },\r\n );\r\n\r\n const tokens = this.mapTokenResponse(response);\r\n await this.tokenManager.setTokens(tokens);\r\n\r\n return tokens;\r\n }\r\n\r\n /**\r\n * Revoke current tokens\r\n */\r\n async revokeToken(): Promise<void> {\r\n const tokens = await this.tokenManager.getTokens();\r\n if (!tokens) return;\r\n\r\n try {\r\n await this.http.postForm(\"/oauth/revoke\", {\r\n token: tokens.accessToken,\r\n client_id: this.config.clientId,\r\n client_secret: this.config.clientSecret,\r\n });\r\n } finally {\r\n await this.tokenManager.clearTokens();\r\n }\r\n }\r\n\r\n /**\r\n * Map OAuth token response to TokenSet\r\n */\r\n private mapTokenResponse(response: TokenResponse): TokenSet {\r\n return {\r\n accessToken: response.access_token,\r\n refreshToken: response.refresh_token,\r\n tokenType: response.token_type,\r\n expiresIn: response.expires_in,\r\n issuedAt: Date.now(),\r\n scope: response.scope,\r\n };\r\n }\r\n}\r\n","import type { TokenStorage } from \"../types\";\r\n\r\n/**\r\n * In-memory storage implementation\r\n * Tokens are lost when page refreshes\r\n */\r\nexport class MemoryStorage implements TokenStorage {\r\n private store = new Map<string, string>();\r\n\r\n async get(key: string): Promise<string | null> {\r\n return this.store.get(key) ?? null;\r\n }\r\n\r\n async set(key: string, value: string): Promise<void> {\r\n this.store.set(key, value);\r\n }\r\n\r\n async remove(key: string): Promise<void> {\r\n this.store.delete(key);\r\n }\r\n\r\n async clear(): Promise<void> {\r\n this.store.clear();\r\n }\r\n}\r\n","import type { TokenStorage } from \"../types\";\r\n\r\n/**\r\n * Browser localStorage implementation\r\n * Tokens persist across browser sessions\r\n */\r\nexport class LocalStorage implements TokenStorage {\r\n private prefix: string;\r\n\r\n constructor(prefix = \"genation\") {\r\n this.prefix = prefix;\r\n }\r\n\r\n private getKey(key: string): string {\r\n return `${this.prefix}:${key}`;\r\n }\r\n\r\n async get(key: string): Promise<string | null> {\r\n if (typeof window === \"undefined\") return null;\r\n return localStorage.getItem(this.getKey(key));\r\n }\r\n\r\n async set(key: string, value: string): Promise<void> {\r\n if (typeof window === \"undefined\") return;\r\n localStorage.setItem(this.getKey(key), value);\r\n }\r\n\r\n async remove(key: string): Promise<void> {\r\n if (typeof window === \"undefined\") return;\r\n localStorage.removeItem(this.getKey(key));\r\n }\r\n\r\n async clear(): Promise<void> {\r\n if (typeof window === \"undefined\") return;\r\n const keys = Object.keys(localStorage).filter((k) =>\r\n k.startsWith(`${this.prefix}:`)\r\n );\r\n keys.forEach((k) => localStorage.removeItem(k));\r\n }\r\n}\r\n","import type { TokenStorage } from \"../types\";\r\n\r\n/**\r\n * Browser sessionStorage implementation\r\n * Tokens persist until browser tab is closed\r\n */\r\nexport class SessionStorage implements TokenStorage {\r\n private prefix: string;\r\n\r\n constructor(prefix = \"genation\") {\r\n this.prefix = prefix;\r\n }\r\n\r\n private getKey(key: string): string {\r\n return `${this.prefix}:${key}`;\r\n }\r\n\r\n async get(key: string): Promise<string | null> {\r\n if (typeof window === \"undefined\") return null;\r\n return sessionStorage.getItem(this.getKey(key));\r\n }\r\n\r\n async set(key: string, value: string): Promise<void> {\r\n if (typeof window === \"undefined\") return;\r\n sessionStorage.setItem(this.getKey(key), value);\r\n }\r\n\r\n async remove(key: string): Promise<void> {\r\n if (typeof window === \"undefined\") return;\r\n sessionStorage.removeItem(this.getKey(key));\r\n }\r\n\r\n async clear(): Promise<void> {\r\n if (typeof window === \"undefined\") return;\r\n const keys = Object.keys(sessionStorage).filter((k) =>\r\n k.startsWith(`${this.prefix}:`)\r\n );\r\n keys.forEach((k) => sessionStorage.removeItem(k));\r\n }\r\n}\r\n","/**\r\n * @fileoverview Storage factory and implementations\r\n * @module storage\r\n */\r\n\r\nimport type { StorageType, TokenStorage } from \"../types\";\r\nimport { MemoryStorage } from \"./memory\";\r\nimport { LocalStorage } from \"./local-storage\";\r\nimport { SessionStorage } from \"./session-storage\";\r\n\r\nexport { MemoryStorage } from \"./memory\";\r\nexport { LocalStorage } from \"./local-storage\";\r\nexport { SessionStorage } from \"./session-storage\";\r\n\r\n/**\r\n * Create a storage instance based on type\r\n *\r\n * @param type - Storage type to create\r\n * @returns Storage implementation\r\n *\r\n * @example\r\n * ```typescript\r\n * const storage = createStorage('localStorage');\r\n * await storage.set('key', 'value');\r\n * ```\r\n */\r\nexport function createStorage(\r\n type: StorageType = \"localStorage\",\r\n): TokenStorage {\r\n switch (type) {\r\n case \"memory\":\r\n return new MemoryStorage();\r\n case \"localStorage\":\r\n return new LocalStorage();\r\n case \"sessionStorage\":\r\n return new SessionStorage();\r\n default:\r\n return new LocalStorage();\r\n }\r\n}\r\n","// Function to convert snake_case to camelCase, handles arrays and objects recursively\r\nexport function snakeToCamel(data: any): any {\r\n if (Array.isArray(data)) {\r\n return data.map(snakeToCamel);\r\n } else if (typeof data === \"object\" && data !== null) {\r\n return Object.fromEntries(\r\n Object.entries(data).map(([key, value]) => [\r\n key.replace(/_([a-z])/g, (_, c) => c.toUpperCase()),\r\n snakeToCamel(value)\r\n ])\r\n );\r\n }\r\n return data;\r\n}","/**\r\n * @fileoverview Main Genation SDK client\r\n * @module client\r\n */\r\n\r\nimport type {\r\n AuthEvent,\r\n AuthStateChangeCallback,\r\n GenationConfig,\r\n Session,\r\n Subscription,\r\n TokenSet,\r\n TokenStorage,\r\n User,\r\n} from \"./types\";\r\nimport { OAuth2Handler, TokenManager } from \"./auth\";\r\nimport { createStorage } from \"./storage\";\r\nimport { ConfigError, HttpClient } from \"./http\";\r\nimport type { License, LicenseResponse } from \"./types/server/license\";\r\nimport type { ApiResponse } from \"./types/server/api-response\";\r\nimport { snakeToCamel } from \"./utils/converter\";\r\n\r\n// Re-export types for convenience\r\nexport type { AuthEvent, AuthStateChangeCallback, Session, Subscription };\r\n\r\n/**\r\n * Main Genation SDK client\r\n *\r\n * OAuth 2.1 authentication client for Genation platform.\r\n * Supports PKCE flow and automatic token refresh.\r\n *\r\n * @example\r\n * ```typescript\r\n * import { createClient } from 'genation';\r\n *\r\n * const client = createClient({\r\n * clientId: 'your-client-id',\r\n * clientSecret: 'your-client-secret',\r\n * redirectUri: 'http://localhost:3000/callback'\r\n * });\r\n *\r\n * // Listen to auth state changes\r\n * const { subscription } = client.onAuthStateChange((event, session) => {\r\n * if (event === 'SIGNED_IN') {\r\n * console.log('User signed in:', session?.user);\r\n * }\r\n * });\r\n *\r\n * // Start login flow\r\n * window.location.href = await client.signIn();\r\n * ```\r\n */\r\nexport class GenationClient {\r\n private oauth: OAuth2Handler;\r\n private tokenManager: TokenManager;\r\n private http: HttpClient;\r\n private httpServer: HttpClient;\r\n private listeners: Set<AuthStateChangeCallback> = new Set();\r\n private initialized = false;\r\n\r\n constructor(config: GenationConfig) {\r\n this.validateConfig(config);\r\n\r\n const storage: TokenStorage = typeof config.storage === \"object\"\r\n ? (config.storage as unknown as TokenStorage)\r\n : createStorage(config.storage);\r\n\r\n this.tokenManager = new TokenManager(storage);\r\n this.oauth = new OAuth2Handler(config, this.tokenManager);\r\n this.http = new HttpClient({\r\n baseUrl: config.authUrl ??\r\n \"https://mnnoheowoowbtpuoguul.supabase.co/auth/v1\",\r\n });\r\n this.httpServer = new HttpClient({\r\n baseUrl: \"https://ff-api.genation.ai/api/v2/client\"\r\n });\r\n }\r\n\r\n private validateConfig(config: GenationConfig): void {\r\n if (!config.clientId) throw ConfigError.missingField(\"clientId\");\r\n if (!config.clientSecret) {\r\n throw ConfigError.missingField(\"clientSecret\");\r\n }\r\n if (!config.redirectUri) throw ConfigError.missingField(\"redirectUri\");\r\n }\r\n\r\n /**\r\n * Emit auth state change event to all listeners\r\n */\r\n private async emitAuthStateChange(event: AuthEvent): Promise<void> {\r\n const session = await this.getSession();\r\n this.listeners.forEach((callback) => {\r\n try {\r\n callback(event, session);\r\n } catch (error) {\r\n console.error(\"Error in auth state change callback:\", error);\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Listen to authentication state changes\r\n *\r\n * Register a callback that fires when:\r\n * - `INITIAL_SESSION`: On first subscription, with current session state\r\n * - `SIGNED_IN`: User successfully authenticated\r\n * - `SIGNED_OUT`: User logged out or session expired\r\n * - `TOKEN_REFRESHED`: Access token was automatically refreshed\r\n *\r\n * @param callback - Function called on each auth state change\r\n * @returns Object containing subscription with `unsubscribe()` method\r\n *\r\n * @example\r\n * ```typescript\r\n * const { subscription } = client.onAuthStateChange((event, session) => {\r\n * console.log('Auth event:', event);\r\n *\r\n * if (event === 'INITIAL_SESSION') {\r\n * // Check if user was previously logged in\r\n * if (session) {\r\n * console.log('Welcome back!', session.user);\r\n * }\r\n * } else if (event === 'SIGNED_IN') {\r\n * // User just signed in\r\n * console.log('Signed in:', session?.user);\r\n * } else if (event === 'SIGNED_OUT') {\r\n * // Clear app state, redirect to login\r\n * console.log('Signed out');\r\n * }\r\n * });\r\n *\r\n * // Cleanup when component unmounts\r\n * subscription.unsubscribe();\r\n * ```\r\n */\r\n onAuthStateChange(\r\n callback: AuthStateChangeCallback,\r\n ): { subscription: Subscription } {\r\n this.listeners.add(callback);\r\n\r\n // Emit INITIAL_SESSION on first subscription\r\n if (!this.initialized) {\r\n this.initialized = true;\r\n setTimeout(() => {\r\n this.emitAuthStateChange(\"INITIAL_SESSION\");\r\n }, 0);\r\n } else {\r\n // For subsequent subscriptions, also emit current state\r\n setTimeout(() => {\r\n this.emitAuthStateChange(\"INITIAL_SESSION\");\r\n }, 0);\r\n }\r\n\r\n return {\r\n subscription: {\r\n unsubscribe: () => {\r\n this.listeners.delete(callback);\r\n },\r\n },\r\n };\r\n }\r\n\r\n /**\r\n * Start OAuth sign-in flow\r\n *\r\n * Generates authorization URL with PKCE challenge.\r\n * Redirect user to this URL to start authentication.\r\n *\r\n * @returns Authorization URL to redirect user to\r\n *\r\n * @example\r\n * ```typescript\r\n * async function handleLogin() {\r\n * const url = await client.signIn();\r\n * window.location.href = url;\r\n * }\r\n * ```\r\n */\r\n async signIn(): Promise<string> {\r\n return this.oauth.getAuthorizationUrl();\r\n }\r\n\r\n /**\r\n * Handle OAuth callback after user authentication\r\n *\r\n * Call this on your redirect URI page to exchange\r\n * the authorization code for access tokens.\r\n * Triggers `SIGNED_IN` event on success.\r\n *\r\n * @param code - Authorization code from URL query params\r\n * @param state - State parameter for CSRF validation\r\n * @returns Token set with access and refresh tokens\r\n * @throws {AuthError} If state mismatch or code exchange fails\r\n *\r\n * @example\r\n * ```typescript\r\n * // On your /callback page\r\n * async function handleCallback() {\r\n * const url = window.location.href;\r\n * await client.handleCallback(url);\r\n * // onAuthStateChange will fire with SIGNED_IN event\r\n * }\r\n * ```\r\n */\r\n async handleCallback(url: string): Promise<TokenSet> {\r\n const params = new URLSearchParams(url);\r\n const code = params.get('code');\r\n const state = params.get('state');\r\n if (!code || !state) {\r\n throw new Error('Missing code or state');\r\n }\r\n const tokens = await this.oauth.exchangeCode(code, state);\r\n await this.emitAuthStateChange(\"SIGNED_IN\");\r\n return tokens;\r\n }\r\n\r\n // /**\r\n // * Sign out and revoke tokens\r\n // *\r\n // * Clears local session and revokes tokens on server.\r\n // * Triggers `SIGNED_OUT` event for all listeners.\r\n // *\r\n // * @example\r\n // * ```typescript\r\n // * async function handleLogout() {\r\n // * await client.signOut();\r\n // * // onAuthStateChange will fire with SIGNED_OUT event\r\n // * }\r\n // * ```\r\n // */\r\n // async signOut(): Promise<void> {\r\n // await this.oauth.revokeToken();\r\n // await this.emitAuthStateChange(\"SIGNED_OUT\");\r\n // }\r\n\r\n /**\r\n * Get current session\r\n *\r\n * Returns session with access token and user info.\r\n * Automatically refreshes token if expired.\r\n *\r\n * @returns Current session or null if not authenticated\r\n *\r\n * @example\r\n * ```typescript\r\n * const session = await client.getSession();\r\n * if (session) {\r\n * console.log('Logged in as:', session.user?.email);\r\n *\r\n * // Use access token for API calls\r\n * fetch('/api/data', {\r\n * headers: { Authorization: `Bearer ${session.accessToken}` }\r\n * });\r\n * }\r\n * ```\r\n */\r\n async getSession(): Promise<Session | null> {\r\n const isExpired = await this.tokenManager.isTokenExpired();\r\n\r\n if (isExpired) {\r\n try {\r\n await this.oauth.refreshToken();\r\n } catch {\r\n return null;\r\n }\r\n }\r\n\r\n const tokens = await this.tokenManager.getTokens();\r\n if (!tokens) return null;\r\n\r\n const user = await this.fetchUser(tokens.accessToken);\r\n\r\n return {\r\n accessToken: tokens.accessToken,\r\n refreshToken: tokens.refreshToken,\r\n expiresIn: tokens.expiresIn,\r\n expiresAt: tokens.issuedAt + tokens.expiresIn * 1000,\r\n user,\r\n };\r\n }\r\n /**\r\n * Get licenses\r\n * @param accessToken - The access token to use for the request\r\n * @param options - The options for the request\r\n * @param options.expiresAfter - Query licenses that are expired after the given date, default set to today to get all valid licenses (unexpired licenses)\r\n * @returns The licenses\r\n */\r\n async getLicenses(options: { expiresAfter?: Date } = {}): Promise<License[] | null> {\r\n const session = await this.getSession();\r\n if (!session) {\r\n return null;\r\n }\r\n const accessToken = session.accessToken;\r\n const { expiresAfter = new Date() } = options;\r\n const response = await this.httpServer.request<ApiResponse<LicenseResponse[]>>(\"/licenses\", {\r\n headers: { Authorization: `Bearer ${accessToken}` },\r\n params: { expiresAfter: expiresAfter.toISOString() }\r\n });\r\n if (!response.ok) {\r\n console.error(\"GenationClient: Error fetching licenses:\", response.error);\r\n return null;\r\n }\r\n const licenses: License[] = snakeToCamel(response.data);\r\n return licenses;\r\n }\r\n /**\r\n * Fetch user info from auth server\r\n */\r\n private async fetchUser(accessToken: string): Promise<User | null> {\r\n try {\r\n // Use standard OIDC UserInfo endpoint\r\n // https://supabase.com/docs/guides/auth/oauth-server/oauth-flows#userinfo-endpoint\r\n const response = await this.http.request<{\r\n sub: string;\r\n email?: string;\r\n name?: string;\r\n picture?: string;\r\n email_verified?: boolean;\r\n phone_number?: string;\r\n phone_number_verified?: boolean;\r\n }>(\"/oauth/userinfo\", {\r\n headers: { Authorization: `Bearer ${accessToken}` },\r\n });\r\n\r\n return {\r\n sub: response.sub,\r\n name: response.name,\r\n picture: response.picture,\r\n email: response.email,\r\n email_verified: response.email_verified,\r\n phone_number: response.phone_number,\r\n phone_number_verified: response.phone_number_verified,\r\n };\r\n } catch (error) {\r\n console.error(\"GenationClient: Error fetching user:\", error);\r\n return null;\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Create a new Genation client instance\r\n *\r\n * Factory function for creating SDK client with configuration.\r\n *\r\n * @param config - Client configuration options\r\n * @returns Configured GenationClient instance\r\n *\r\n * @example\r\n * ```typescript\r\n * import { createClient } from 'genation';\r\n *\r\n * const client = createClient({\r\n * clientId: 'your-client-id',\r\n * clientSecret: 'your-client-secret',\r\n * redirectUri: 'http://localhost:3000/callback',\r\n * // Optional\r\n * scopes: ['openid', 'profile', 'email'],\r\n * storage: 'localStorage',\r\n * });\r\n * ```\r\n */\r\nexport function createClient(config: GenationConfig): GenationClient {\r\n return new GenationClient(config);\r\n}\r\n"],"names":["GenationError","message","code","cause","AuthError","NetworkError","status","response","ConfigError","field","HttpClient","config","endpoint","options","method","headers","body","params","url","searchParams","controller","timeoutId","error","data","base64URLEncode","buffer","generateCodeVerifier","array","generateCodeChallenge","verifier","hash","generatePKCE","codeVerifier","codeChallenge","generateState","TOKEN_KEY","PKCE_KEY","STATE_KEY","TokenManager","storage","tokens","expiresAt","state","DEFAULT_AUTH_URL","OAuth2Handler","tokenManager","pkce","storedState","currentTokens","MemoryStorage","key","value","LocalStorage","prefix","k","SessionStorage","createStorage","type","snakeToCamel","_","c","GenationClient","event","session","callback","user","accessToken","expiresAfter","createClient"],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -214,18 +214,13 @@ export declare class GenationClient {
214
214
  * ```typescript
215
215
  * // On your /callback page
216
216
  * async function handleCallback() {
217
- * const params = new URLSearchParams(window.location.search);
218
- * const code = params.get('code');
219
- * const state = params.get('state');
220
- *
221
- * if (code && state) {
222
- * await client.handleCallback(code, state);
223
- * // onAuthStateChange will fire with SIGNED_IN event
224
- * }
217
+ * const url = window.location.href;
218
+ * await client.handleCallback(url);
219
+ * // onAuthStateChange will fire with SIGNED_IN event
225
220
  * }
226
221
  * ```
227
222
  */
228
- handleCallback(code: string, state: string): Promise<TokenSet>;
223
+ handleCallback(url: string): Promise<TokenSet>;
229
224
  /**
230
225
  * Get current session
231
226
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@genation/sdk",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "OAuth 2.1 SDK for Genation authentication",
5
5
  "type": "module",
6
6
  "main": "./dist/genation.cjs.js",
@@ -8,9 +8,9 @@
8
8
  "types": "./dist/index.d.ts",
9
9
  "exports": {
10
10
  ".": {
11
+ "types": "./dist/index.d.ts",
11
12
  "import": "./dist/genation.es.js",
12
- "require": "./dist/genation.cjs.js",
13
- "types": "./dist/index.d.ts"
13
+ "require": "./dist/genation.cjs.js"
14
14
  }
15
15
  },
16
16
  "files": [