@genation/sdk 0.2.0 → 0.2.1
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 +6 -10
- package/dist/genation.cjs.js +1 -1
- package/dist/genation.cjs.js.map +1 -1
- package/dist/genation.es.js +62 -64
- package/dist/genation.es.js.map +1 -1
- package/dist/genation.umd.js +1 -1
- package/dist/genation.umd.js.map +1 -1
- package/dist/index.d.ts +4 -9
- package/package.json +1 -1
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(
|
|
85
|
+
### `client.handleCallback(url)`
|
|
89
86
|
|
|
90
87
|
Exchange authorization code for tokens.
|
|
91
88
|
|
|
92
89
|
```typescript
|
|
93
|
-
const
|
|
94
|
-
await client.handleCallback(
|
|
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
|
-
|
|
122
|
-
email?: string;
|
|
118
|
+
sub: string; // user id
|
|
123
119
|
name?: string;
|
|
124
|
-
|
|
125
|
-
|
|
120
|
+
email?: string;
|
|
121
|
+
...
|
|
126
122
|
}
|
|
127
123
|
```
|
|
128
124
|
|
package/dist/genation.cjs.js
CHANGED
|
@@ -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:
|
|
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:o,params:i}=t;let c=`${this.baseUrl}${e}`;if(i){const a=new URLSearchParams(i);c+=`?${a.toString()}`}const S=new AbortController,T=setTimeout(()=>S.abort(),this.timeout);try{const a=await fetch(c,{method:n,headers:{"Content-Type":"application/json",...s},body:o?JSON.stringify(o):void 0,signal:S.signal});if(clearTimeout(T),!a.ok)throw h.fromResponse(a);return await a.json()}catch(a){throw clearTimeout(T),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 s=`${this.baseUrl}${e}`,o=new AbortController,i=setTimeout(()=>o.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:o.signal});if(clearTimeout(i),!c.ok)throw h.fromResponse(c);return await c.json()}catch(c){throw clearTimeout(i),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 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}),i=this.mapTokenResponse(o);return await this.tokenManager.setTokens(i),i}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){const t=new URLSearchParams(e),n=t.get("code"),s=t.get("state");if(!n||!s)throw new Error("Missing code or state");const o=await this.oauth.exchangeCode(n,s);try{const i=await this.fetchUser(o.accessToken);console.log("Debug: handleCallback fetched user:",i)}catch(i){console.error("Debug: handleCallback fetchUser failed:",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:s=new Date}=e,o=await this.httpServer.request("/licenses",{headers:{Authorization:`Bearer ${n}`},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 i=k(o.data);return console.log("GenationClient: Licenses:",i),i}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=_;
|
|
2
2
|
//# sourceMappingURL=genation.cjs.js.map
|
package/dist/genation.cjs.js.map
CHANGED
|
@@ -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\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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"}
|
package/dist/genation.es.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
class m extends Error {
|
|
2
2
|
code;
|
|
3
3
|
cause;
|
|
4
|
-
constructor(e, t,
|
|
5
|
-
super(e), this.name = "GenationError", this.code = t, this.cause =
|
|
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,
|
|
10
|
-
super(e, t,
|
|
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,
|
|
31
|
-
super(e, "network_error",
|
|
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,50 +55,50 @@ class p {
|
|
|
55
55
|
* Make an HTTP request
|
|
56
56
|
*/
|
|
57
57
|
async request(e, t = {}) {
|
|
58
|
-
const { method:
|
|
58
|
+
const { method: s = "GET", headers: n = {}, body: i, params: o } = t;
|
|
59
59
|
let c = `${this.baseUrl}${e}`;
|
|
60
|
-
if (
|
|
61
|
-
const
|
|
62
|
-
c += `?${
|
|
60
|
+
if (o) {
|
|
61
|
+
const a = new URLSearchParams(o);
|
|
62
|
+
c += `?${a.toString()}`;
|
|
63
63
|
}
|
|
64
64
|
const y = new AbortController(), S = setTimeout(() => y.abort(), this.timeout);
|
|
65
65
|
try {
|
|
66
|
-
const
|
|
67
|
-
method:
|
|
66
|
+
const a = await fetch(c, {
|
|
67
|
+
method: s,
|
|
68
68
|
headers: {
|
|
69
69
|
"Content-Type": "application/json",
|
|
70
|
-
...
|
|
70
|
+
...n
|
|
71
71
|
},
|
|
72
72
|
body: i ? JSON.stringify(i) : void 0,
|
|
73
73
|
signal: y.signal
|
|
74
74
|
});
|
|
75
|
-
if (clearTimeout(S), !
|
|
76
|
-
throw h.fromResponse(
|
|
77
|
-
return await
|
|
78
|
-
} catch (
|
|
79
|
-
throw clearTimeout(S),
|
|
75
|
+
if (clearTimeout(S), !a.ok)
|
|
76
|
+
throw h.fromResponse(a);
|
|
77
|
+
return await a.json();
|
|
78
|
+
} catch (a) {
|
|
79
|
+
throw clearTimeout(S), 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);
|
|
80
80
|
}
|
|
81
81
|
}
|
|
82
82
|
/**
|
|
83
83
|
* POST request with form data (for OAuth token exchange)
|
|
84
84
|
*/
|
|
85
|
-
async postForm(e, t,
|
|
86
|
-
const
|
|
85
|
+
async postForm(e, t, s = {}) {
|
|
86
|
+
const n = `${this.baseUrl}${e}`, i = new AbortController(), o = setTimeout(() => i.abort(), this.timeout);
|
|
87
87
|
try {
|
|
88
|
-
const c = await fetch(
|
|
88
|
+
const c = await fetch(n, {
|
|
89
89
|
method: "POST",
|
|
90
90
|
headers: {
|
|
91
91
|
"Content-Type": "application/x-www-form-urlencoded",
|
|
92
|
-
...
|
|
92
|
+
...s
|
|
93
93
|
},
|
|
94
94
|
body: new URLSearchParams(t).toString(),
|
|
95
95
|
signal: i.signal
|
|
96
96
|
});
|
|
97
|
-
if (clearTimeout(
|
|
97
|
+
if (clearTimeout(o), !c.ok)
|
|
98
98
|
throw h.fromResponse(c);
|
|
99
99
|
return await c.json();
|
|
100
100
|
} catch (c) {
|
|
101
|
-
throw clearTimeout(
|
|
101
|
+
throw clearTimeout(o), c instanceof h ? c : new h("Network request failed", void 0, c);
|
|
102
102
|
}
|
|
103
103
|
}
|
|
104
104
|
}
|
|
@@ -110,8 +110,8 @@ function b() {
|
|
|
110
110
|
return crypto.getRandomValues(r), k(r);
|
|
111
111
|
}
|
|
112
112
|
async function C(r) {
|
|
113
|
-
const t = new TextEncoder().encode(r),
|
|
114
|
-
return k(new Uint8Array(
|
|
113
|
+
const t = new TextEncoder().encode(r), s = await crypto.subtle.digest("SHA-256", t);
|
|
114
|
+
return k(new Uint8Array(s));
|
|
115
115
|
}
|
|
116
116
|
async function _() {
|
|
117
117
|
const r = b(), e = await C(r);
|
|
@@ -218,7 +218,7 @@ class x {
|
|
|
218
218
|
async getAuthorizationUrl() {
|
|
219
219
|
const e = await _(), t = v();
|
|
220
220
|
await this.tokenManager.setPKCE(e.codeVerifier), await this.tokenManager.setState(t);
|
|
221
|
-
const
|
|
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 &&
|
|
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
|
|
236
|
-
if (!
|
|
235
|
+
const s = await this.tokenManager.consumeState();
|
|
236
|
+
if (!s || s !== t)
|
|
237
237
|
throw l.invalidState();
|
|
238
|
-
const
|
|
239
|
-
if (!
|
|
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:
|
|
249
|
+
code_verifier: n
|
|
250
250
|
}
|
|
251
|
-
),
|
|
252
|
-
return await this.tokenManager.setTokens(
|
|
251
|
+
), o = this.mapTokenResponse(i);
|
|
252
|
+
return await this.tokenManager.setTokens(o), o;
|
|
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
|
-
),
|
|
270
|
-
return await this.tokenManager.setTokens(
|
|
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, (
|
|
380
|
+
e.replace(/_([a-z])/g, (s, n) => n.toUpperCase()),
|
|
381
381
|
w(t)
|
|
382
382
|
])
|
|
383
383
|
) : r;
|
|
@@ -409,11 +409,11 @@ class K {
|
|
|
409
409
|
*/
|
|
410
410
|
async emitAuthStateChange(e) {
|
|
411
411
|
const t = await this.getSession();
|
|
412
|
-
this.listeners.forEach((
|
|
412
|
+
this.listeners.forEach((s) => {
|
|
413
413
|
try {
|
|
414
|
-
|
|
415
|
-
} catch (
|
|
416
|
-
console.error("Error in auth state change callback:",
|
|
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,24 @@ class K {
|
|
|
500
500
|
* ```typescript
|
|
501
501
|
* // On your /callback page
|
|
502
502
|
* async function handleCallback() {
|
|
503
|
-
* const
|
|
504
|
-
*
|
|
505
|
-
*
|
|
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
|
|
515
|
-
const
|
|
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);
|
|
516
514
|
try {
|
|
517
|
-
const
|
|
518
|
-
console.log("Debug: handleCallback fetched user:",
|
|
519
|
-
} catch (
|
|
520
|
-
console.error("Debug: handleCallback fetchUser failed:",
|
|
515
|
+
const o = await this.fetchUser(i.accessToken);
|
|
516
|
+
console.log("Debug: handleCallback fetched user:", o);
|
|
517
|
+
} catch (o) {
|
|
518
|
+
console.error("Debug: handleCallback fetchUser failed:", o);
|
|
521
519
|
}
|
|
522
|
-
return await this.emitAuthStateChange("SIGNED_IN"),
|
|
520
|
+
return await this.emitAuthStateChange("SIGNED_IN"), i;
|
|
523
521
|
}
|
|
524
522
|
// /**
|
|
525
523
|
// * Sign out and revoke tokens
|
|
@@ -569,13 +567,13 @@ class K {
|
|
|
569
567
|
}
|
|
570
568
|
const t = await this.tokenManager.getTokens();
|
|
571
569
|
if (!t) return null;
|
|
572
|
-
const
|
|
570
|
+
const s = await this.fetchUser(t.accessToken);
|
|
573
571
|
return {
|
|
574
572
|
accessToken: t.accessToken,
|
|
575
573
|
refreshToken: t.refreshToken,
|
|
576
574
|
expiresIn: t.expiresIn,
|
|
577
575
|
expiresAt: t.issuedAt + t.expiresIn * 1e3,
|
|
578
|
-
user:
|
|
576
|
+
user: s
|
|
579
577
|
};
|
|
580
578
|
}
|
|
581
579
|
/**
|
|
@@ -589,15 +587,15 @@ class K {
|
|
|
589
587
|
const t = await this.getSession();
|
|
590
588
|
if (!t)
|
|
591
589
|
return null;
|
|
592
|
-
const
|
|
593
|
-
headers: { Authorization: `Bearer ${
|
|
594
|
-
params: { expiresAfter:
|
|
590
|
+
const s = t.accessToken, { expiresAfter: n = /* @__PURE__ */ new Date() } = e, i = await this.httpServer.request("/licenses", {
|
|
591
|
+
headers: { Authorization: `Bearer ${s}` },
|
|
592
|
+
params: { expiresAfter: n.toISOString() }
|
|
595
593
|
});
|
|
596
594
|
if (!i.ok)
|
|
597
595
|
return console.error("GenationClient: Error fetching licenses:", i.error), null;
|
|
598
596
|
console.log("GenationClient: Response data:", i.data);
|
|
599
|
-
const
|
|
600
|
-
return console.log("GenationClient: Licenses:",
|
|
597
|
+
const o = w(i.data);
|
|
598
|
+
return console.log("GenationClient: Licenses:", o), o;
|
|
601
599
|
}
|
|
602
600
|
/**
|
|
603
601
|
* Fetch user info from auth server
|
package/dist/genation.es.js.map
CHANGED
|
@@ -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\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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"}
|
package/dist/genation.umd.js
CHANGED
|
@@ -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,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 g extends d{constructor(e){super(e,"config_error"),this.name="ConfigError"}static missingField(e){return new g(`Missing required config field: ${e}`)}}class f{baseUrl;timeout;constructor(e){this.baseUrl=e.baseUrl.replace(/\/$/,""),this.timeout=e.timeout??3e4}async request(e,t={}){const{method:r="GET",headers:i={},body:o,params:a}=t;let u=`${this.baseUrl}${e}`;if(a){const c=new URLSearchParams(a);u+=`?${c.toString()}`}const v=new AbortController,E=setTimeout(()=>v.abort(),this.timeout);try{const c=await fetch(u,{method:r,headers:{"Content-Type":"application/json",...i},body:o?JSON.stringify(o):void 0,signal:v.signal});if(clearTimeout(E),!c.ok)throw l.fromResponse(c);return await c.json()}catch(c){throw clearTimeout(E),c instanceof l?c:c instanceof Error&&c.name==="AbortError"?new l("Request timeout",void 0,c):new l("Network request failed",void 0,c)}}async postForm(e,t,r={}){const i=`${this.baseUrl}${e}`,o=new AbortController,a=setTimeout(()=>o.abort(),this.timeout);try{const u=await fetch(i,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded",...r},body:new URLSearchParams(t).toString(),signal:o.signal});if(clearTimeout(a),!u.ok)throw l.fromResponse(u);return await u.json()}catch(u){throw clearTimeout(a),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 f({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 i=await this.tokenManager.consumePKCE();if(!i)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:i}),a=this.mapTokenResponse(o);return await this.tokenManager.setTokens(a),a}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,i)=>i.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 f({baseUrl:e.authUrl??"https://mnnoheowoowbtpuoguul.supabase.co/auth/v1"}),this.httpServer=new f({baseUrl:"https://ff-api.genation.ai/api/v2/client"})}validateConfig(e){if(!e.clientId)throw g.missingField("clientId");if(!e.clientSecret)throw g.missingField("clientSecret");if(!e.redirectUri)throw g.missingField("redirectUri")}async emitAuthStateChange(e){const t=await this.getSession();this.listeners.forEach(r=>{try{r(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),r=t.get("code"),i=t.get("state");if(!r||!i)throw new Error("Missing code or state");const o=await this.oauth.exchangeCode(r,i);try{const a=await this.fetchUser(o.accessToken);console.log("Debug: handleCallback fetched user:",a)}catch(a){console.error("Debug: handleCallback fetchUser failed:",a)}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 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:i=new Date}=e,o=await this.httpServer.request("/licenses",{headers:{Authorization:`Bearer ${r}`},params:{expiresAfter:i.toISOString()}});if(!o.ok)return console.error("GenationClient: Error fetching licenses:",o.error),null;console.log("GenationClient: Response data:",o.data);const a=S(o.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(n){return new _(n)}s.AuthError=h,s.ConfigError=g,s.GenationClient=_,s.GenationError=d,s.LocalStorage=k,s.MemoryStorage=T,s.NetworkError=l,s.SessionStorage=b,s.createClient=R,s.createStorage=C,Object.defineProperty(s,Symbol.toStringTag,{value:"Module"})}));
|
|
2
2
|
//# sourceMappingURL=genation.umd.js.map
|
package/dist/genation.umd.js.map
CHANGED
|
@@ -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\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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"}
|
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
|
|
218
|
-
*
|
|
219
|
-
*
|
|
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(
|
|
223
|
+
handleCallback(url: string): Promise<TokenSet>;
|
|
229
224
|
/**
|
|
230
225
|
* Get current session
|
|
231
226
|
*
|