@insforge/sdk 1.0.1-refresh.5 → 1.0.1-refresh.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +56 -6
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +56 -6
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/types.ts","../src/lib/http-client.ts","../src/lib/session-storage.ts","../src/lib/token-manager.ts","../src/modules/database-postgrest.ts","../src/modules/auth.ts","../src/modules/storage.ts","../src/modules/ai.ts","../src/modules/functions.ts","../src/client.ts"],"sourcesContent":["/**\r\n * @insforge/sdk - TypeScript SDK for InsForge Backend-as-a-Service\r\n * \r\n * @packageDocumentation\r\n */\r\n\r\n// Main client\r\nexport { InsForgeClient } from './client';\r\n\r\n// Types\r\nexport type {\r\n InsForgeConfig,\r\n InsForgeConfig as ClientOptions, // Alias for compatibility\r\n TokenStorage,\r\n AuthSession,\r\n ApiError,\r\n} from './types';\r\n\r\nexport { InsForgeError } from './types';\r\n\r\n// Re-export shared schemas that SDK users will need\r\nexport type {\r\n UserSchema,\r\n CreateUserRequest,\r\n CreateSessionRequest,\r\n AuthErrorResponse,\r\n} from '@insforge/shared-schemas';\r\n\r\n// Re-export auth module for advanced usage\r\nexport { Auth } from './modules/auth';\r\n\r\nexport type { ProfileData, UpdateProfileData } from './modules/auth';\r\n\r\n// Re-export database module (using postgrest-js)\r\nexport { Database } from './modules/database-postgrest';\r\n// Note: QueryBuilder is no longer exported as we use postgrest-js QueryBuilder internally\r\n\r\n// Re-export storage module and types\r\nexport { Storage, StorageBucket } from './modules/storage';\r\nexport type { StorageResponse } from './modules/storage';\r\n\r\n// Re-export AI module\r\nexport { AI } from './modules/ai';\r\n\r\n// Re-export Functions module\r\nexport { Functions } from './modules/functions';\r\nexport type { FunctionInvokeOptions } from './modules/functions';\r\n\r\n// Re-export utilities for advanced usage\r\nexport { HttpClient } from './lib/http-client';\r\nexport { TokenManager } from './lib/token-manager';\r\n\r\n// Re-export session storage strategies for advanced usage\r\nexport {\r\n SecureSessionStorage,\r\n LocalSessionStorage,\r\n} from './lib/session-storage';\r\nexport type { SessionStorageStrategy } from './lib/session-storage';\r\n\r\n// Factory function for creating clients (Supabase-style)\r\nimport { InsForgeClient } from './client';\r\nimport { InsForgeConfig } from './types';\r\n\r\nexport function createClient(config: InsForgeConfig): InsForgeClient {\r\n return new InsForgeClient(config);\r\n}\r\n\r\n// Default export for convenience\r\nexport default InsForgeClient;\r\n","/**\r\n * InsForge SDK Types - only SDK-specific types here\r\n * Use @insforge/shared-schemas directly for API types\r\n */\r\n\r\nimport type { UserSchema } from '@insforge/shared-schemas';\r\n\r\nexport interface InsForgeConfig {\r\n /**\r\n * The base URL of the InsForge backend API\r\n * @default \"http://localhost:7130\"\r\n */\r\n baseUrl?: string;\r\n\r\n /**\r\n * Anonymous API key (optional)\r\n * Used for public/unauthenticated requests when no user token is set\r\n */\r\n anonKey?: string;\r\n\r\n /**\r\n * Edge Function Token (optional)\r\n * Use this when running in edge functions/serverless with a user's JWT token\r\n * This token will be used for all authenticated requests\r\n */\r\n edgeFunctionToken?: string;\r\n\r\n /**\r\n * Custom fetch implementation (useful for Node.js environments)\r\n */\r\n fetch?: typeof fetch;\r\n\r\n /**\r\n * Storage adapter for persisting tokens\r\n */\r\n storage?: TokenStorage;\r\n\r\n /**\r\n * Whether to automatically refresh tokens before they expire\r\n * @default true\r\n */\r\n autoRefreshToken?: boolean;\r\n\r\n /**\r\n * Whether to persist session in storage\r\n * @default true\r\n */\r\n persistSession?: boolean;\r\n\r\n /**\r\n * Custom headers to include with every request\r\n */\r\n headers?: Record<string, string>;\r\n}\r\n\r\nexport interface TokenStorage {\r\n getItem(key: string): string | null | Promise<string | null>;\r\n setItem(key: string, value: string): void | Promise<void>;\r\n removeItem(key: string): void | Promise<void>;\r\n}\r\n\r\nexport interface AuthSession {\r\n user: UserSchema;\r\n accessToken: string;\r\n expiresAt?: Date;\r\n}\r\n\r\nexport interface ApiError {\r\n error: string;\r\n message: string;\r\n statusCode: number;\r\n nextActions?: string;\r\n}\r\n\r\nexport class InsForgeError extends Error {\r\n public statusCode: number;\r\n public error: string;\r\n public nextActions?: string;\r\n\r\n constructor(message: string, statusCode: number, error: string, nextActions?: string) {\r\n super(message);\r\n this.name = 'InsForgeError';\r\n this.statusCode = statusCode;\r\n this.error = error;\r\n this.nextActions = nextActions;\r\n }\r\n\r\n static fromApiError(apiError: ApiError): InsForgeError {\r\n return new InsForgeError(\r\n apiError.message,\r\n apiError.statusCode,\r\n apiError.error,\r\n apiError.nextActions\r\n );\r\n }\r\n}","import { InsForgeConfig, ApiError, InsForgeError } from '../types';\r\n\r\nexport interface RequestOptions extends RequestInit {\r\n params?: Record<string, string>;\r\n}\r\n\r\n/**\r\n * Callback type for token refresh\r\n * Returns new access token or null if refresh failed\r\n */\r\nexport type RefreshCallback = () => Promise<string | null>;\r\n\r\nexport class HttpClient {\r\n public readonly baseUrl: string;\r\n public readonly fetch: typeof fetch;\r\n private defaultHeaders: Record<string, string>;\r\n private anonKey: string | undefined;\r\n private userToken: string | null = null;\r\n \r\n // Auto-refresh support\r\n private refreshCallback?: RefreshCallback;\r\n private isRefreshing = false;\r\n private refreshQueue: Array<{\r\n resolve: (token: string) => void;\r\n reject: (error: Error) => void;\r\n }> = [];\r\n\r\n constructor(config: InsForgeConfig) {\r\n this.baseUrl = config.baseUrl || 'http://localhost:7130';\r\n // Properly bind fetch to maintain its context\r\n this.fetch = config.fetch || (globalThis.fetch ? globalThis.fetch.bind(globalThis) : undefined as any);\r\n this.anonKey = config.anonKey;\r\n this.defaultHeaders = {\r\n ...config.headers,\r\n };\r\n\r\n if (!this.fetch) {\r\n throw new Error(\r\n 'Fetch is not available. Please provide a fetch implementation in the config.'\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Set the refresh callback for automatic token refresh on 401\r\n */\r\n setRefreshCallback(callback: RefreshCallback): void {\r\n this.refreshCallback = callback;\r\n }\r\n\r\n private buildUrl(path: string, params?: Record<string, string>): string {\r\n const url = new URL(path, this.baseUrl);\r\n if (params) {\r\n Object.entries(params).forEach(([key, value]) => {\r\n // For select parameter, preserve the exact formatting by normalizing whitespace\r\n // This ensures PostgREST relationship queries work correctly\r\n if (key === 'select') {\r\n // Normalize multiline select strings for PostgREST:\r\n // 1. Replace all whitespace (including newlines) with single space\r\n // 2. Remove spaces inside parentheses for proper PostgREST syntax\r\n // 3. Keep spaces after commas at the top level for readability\r\n let normalizedValue = value.replace(/\\s+/g, ' ').trim();\r\n \r\n // Fix spaces around parentheses and inside them\r\n normalizedValue = normalizedValue\r\n .replace(/\\s*\\(\\s*/g, '(') // Remove spaces around opening parens\r\n .replace(/\\s*\\)\\s*/g, ')') // Remove spaces around closing parens\r\n .replace(/\\(\\s+/g, '(') // Remove spaces after opening parens\r\n .replace(/\\s+\\)/g, ')') // Remove spaces before closing parens\r\n .replace(/,\\s+(?=[^()]*\\))/g, ','); // Remove spaces after commas inside parens\r\n \r\n url.searchParams.append(key, normalizedValue);\r\n } else {\r\n url.searchParams.append(key, value);\r\n }\r\n });\r\n }\r\n return url.toString();\r\n }\r\n\r\n async request<T>(\r\n method: string,\r\n path: string,\r\n options: RequestOptions = {}\r\n ): Promise<T> {\r\n return this.performRequest<T>(method, path, options, false);\r\n }\r\n\r\n private async performRequest<T>(\r\n method: string,\r\n path: string,\r\n options: RequestOptions = {},\r\n isRetry = false\r\n ): Promise<T> {\r\n const { params, headers = {}, body, ...fetchOptions } = options;\r\n \r\n const url = this.buildUrl(path, params);\r\n \r\n const requestHeaders: Record<string, string> = {\r\n ...this.defaultHeaders,\r\n };\r\n \r\n // Set Authorization header: prefer user token, fallback to anon key\r\n const authToken = this.userToken || this.anonKey;\r\n if (authToken) {\r\n requestHeaders['Authorization'] = `Bearer ${authToken}`;\r\n }\r\n \r\n // Handle body serialization\r\n let processedBody: any;\r\n if (body !== undefined) {\r\n // Check if body is FormData (for file uploads)\r\n if (typeof FormData !== 'undefined' && body instanceof FormData) {\r\n // Don't set Content-Type for FormData, let browser set it with boundary\r\n processedBody = body;\r\n } else {\r\n // JSON body\r\n if (method !== 'GET') {\r\n requestHeaders['Content-Type'] = 'application/json;charset=UTF-8';\r\n }\r\n processedBody = JSON.stringify(body);\r\n }\r\n }\r\n \r\n Object.assign(requestHeaders, headers);\r\n \r\n const response = await this.fetch(url, {\r\n method,\r\n headers: requestHeaders,\r\n body: processedBody,\r\n ...fetchOptions,\r\n credentials: 'include',\r\n });\r\n\r\n // Handle 401 with automatic refresh (only if we have a refresh callback and this isn't already a retry)\r\n const isRefreshEndpoint = path.includes('/api/auth/refresh') || path.includes('/api/auth/logout');\r\n if (response.status === 401 && !isRetry && !isRefreshEndpoint && this.refreshCallback) {\r\n const newToken = await this.handleTokenRefresh();\r\n if (newToken) {\r\n this.setAuthToken(newToken);\r\n return this.performRequest<T>(method, path, options, true);\r\n }\r\n }\r\n\r\n // Handle 204 No Content\r\n if (response.status === 204) {\r\n return undefined as T;\r\n }\r\n\r\n // Try to parse JSON response\r\n let data: any;\r\n const contentType = response.headers.get('content-type');\r\n // Check for any JSON content type (including PostgREST's vnd.pgrst.object+json)\r\n if (contentType?.includes('json')) {\r\n data = await response.json();\r\n } else {\r\n // For non-JSON responses, return text\r\n data = await response.text();\r\n }\r\n\r\n // Handle errors\r\n if (!response.ok) {\r\n if (data && typeof data === 'object' && 'error' in data) {\r\n // Add the HTTP status code if not already in the data\r\n if (!data.statusCode && !data.status) {\r\n data.statusCode = response.status;\r\n }\r\n const error = InsForgeError.fromApiError(data as ApiError);\r\n // Preserve all additional fields from the error response\r\n Object.keys(data).forEach(key => {\r\n if (key !== 'error' && key !== 'message' && key !== 'statusCode') {\r\n (error as any)[key] = data[key];\r\n }\r\n });\r\n throw error;\r\n }\r\n throw new InsForgeError(\r\n `Request failed: ${response.statusText}`,\r\n response.status,\r\n 'REQUEST_FAILED'\r\n );\r\n }\r\n\r\n return data as T;\r\n }\r\n\r\n /**\r\n * Handle token refresh with queue to prevent duplicate refreshes\r\n * Multiple concurrent 401s will wait for a single refresh to complete\r\n */\r\n private async handleTokenRefresh(): Promise<string | null> {\r\n // If already refreshing, queue this request\r\n if (this.isRefreshing) {\r\n return new Promise((resolve, reject) => {\r\n this.refreshQueue.push({ resolve, reject });\r\n });\r\n }\r\n\r\n this.isRefreshing = true;\r\n\r\n try {\r\n const newToken = await this.refreshCallback?.();\r\n \r\n // Resolve all queued requests with the new token (or null if refresh failed)\r\n this.refreshQueue.forEach(({ resolve, reject }) => {\r\n if (newToken) {\r\n resolve(newToken);\r\n } else {\r\n reject(new Error('Token refresh failed'));\r\n }\r\n });\r\n this.refreshQueue = [];\r\n \r\n return newToken || null;\r\n } catch (error) {\r\n // Reject all queued requests\r\n this.refreshQueue.forEach(({ reject }) => {\r\n reject(error instanceof Error ? error : new Error('Token refresh failed'));\r\n });\r\n this.refreshQueue = [];\r\n \r\n return null;\r\n } finally {\r\n this.isRefreshing = false;\r\n }\r\n }\r\n\r\n get<T>(path: string, options?: RequestOptions): Promise<T> {\r\n return this.request<T>('GET', path, options);\r\n }\r\n\r\n post<T>(path: string, body?: any, options?: RequestOptions): Promise<T> {\r\n return this.request<T>('POST', path, { ...options, body });\r\n }\r\n\r\n put<T>(path: string, body?: any, options?: RequestOptions): Promise<T> {\r\n return this.request<T>('PUT', path, { ...options, body });\r\n }\r\n\r\n patch<T>(path: string, body?: any, options?: RequestOptions): Promise<T> {\r\n return this.request<T>('PATCH', path, { ...options, body });\r\n }\r\n\r\n delete<T>(path: string, options?: RequestOptions): Promise<T> {\r\n return this.request<T>('DELETE', path, options);\r\n }\r\n\r\n setAuthToken(token: string | null) {\r\n this.userToken = token;\r\n }\r\n\r\n getHeaders(): Record<string, string> {\r\n const headers = { ...this.defaultHeaders };\r\n \r\n // Include Authorization header if token is available (same logic as request method)\r\n const authToken = this.userToken || this.anonKey;\r\n if (authToken) {\r\n headers['Authorization'] = `Bearer ${authToken}`;\r\n }\r\n \r\n return headers;\r\n }\r\n}\r\n","/**\n * Session Storage Strategies for InsForge SDK\n * \n * Implements the Strategy Pattern for token storage:\n * - SecureSessionStorage: In-memory tokens + httpOnly cookie refresh (XSS-resistant)\n * - LocalSessionStorage: localStorage-based storage (legacy/fallback)\n */\n\nimport type { UserSchema } from '@insforge/shared-schemas';\nimport type { AuthSession, TokenStorage } from '../types';\n\n// localStorage keys for persistent storage\nexport const TOKEN_KEY = 'insforge-auth-token';\nexport const USER_KEY = 'insforge-auth-user';\n\n// Cookie name for optimistic refresh flag\nexport const AUTH_FLAG_COOKIE = 'isAuthenticated';\n\n/**\n * Strategy interface for session storage\n * All storage implementations must conform to this interface\n */\nexport interface SessionStorageStrategy {\n /** Save complete session (token + user) */\n saveSession(session: AuthSession): void;\n \n /** Get current session */\n getSession(): AuthSession | null;\n \n /** Get access token only */\n getAccessToken(): string | null;\n \n /** Update access token (e.g., after refresh) */\n setAccessToken(token: string): void;\n \n /** Get user data */\n getUser(): UserSchema | null;\n \n /** Update user data */\n setUser(user: UserSchema): void;\n \n /** Clear all session data */\n clearSession(): void;\n \n /** Check if token refresh should be attempted (e.g., on page reload) */\n shouldAttemptRefresh(): boolean;\n \n /** Get strategy identifier for debugging */\n readonly strategyId: string;\n}\n\n/**\n * Secure Session Storage Strategy\n * \n * Stores access token in memory only (cleared on page refresh).\n * Refresh token is stored in httpOnly cookie by the backend (on backend domain).\n * The `isAuthenticated` cookie is set by the SDK on the frontend domain to signal\n * that a secure session exists and token refresh should be attempted on page reload.\n * \n * Security benefits:\n * - Access token not accessible to XSS attacks (in memory only)\n * - Refresh token completely inaccessible to JavaScript (httpOnly)\n */\nexport class SecureSessionStorage implements SessionStorageStrategy {\n readonly strategyId = 'secure';\n \n private accessToken: string | null = null;\n private user: UserSchema | null = null;\n\n saveSession(session: AuthSession): void {\n this.accessToken = session.accessToken;\n this.user = session.user;\n }\n\n getSession(): AuthSession | null {\n if (!this.accessToken || !this.user) return null;\n return {\n accessToken: this.accessToken,\n user: this.user,\n };\n }\n\n getAccessToken(): string | null {\n return this.accessToken;\n }\n\n setAccessToken(token: string): void {\n this.accessToken = token;\n }\n\n getUser(): UserSchema | null {\n return this.user;\n }\n\n setUser(user: UserSchema): void {\n this.user = user;\n }\n\n clearSession(): void {\n this.accessToken = null;\n this.user = null;\n }\n\n shouldAttemptRefresh(): boolean {\n // Attempt refresh if:\n // 1. No token in memory (page was refreshed)\n // 2. Auth flag cookie exists (SDK set it on frontend domain after successful auth)\n if (this.accessToken) return false;\n return this.hasAuthFlag();\n }\n\n // --- Private: Auth Flag Cookie Detection (SDK-managed on frontend domain) ---\n\n private hasAuthFlag(): boolean {\n if (typeof document === 'undefined') return false;\n return document.cookie.split(';').some(c => \n c.trim().startsWith(`${AUTH_FLAG_COOKIE}=`)\n );\n }\n}\n\n/**\n * Local Session Storage Strategy\n * \n * Stores tokens in localStorage for persistence across page reloads.\n * Used for legacy backends or environments where httpOnly cookies aren't available.\n * \n * Note: This approach exposes tokens to XSS attacks. Use SecureSessionStorage\n * when possible.\n */\nexport class LocalSessionStorage implements SessionStorageStrategy {\n readonly strategyId = 'local';\n \n private storage: TokenStorage;\n\n constructor(storage?: TokenStorage) {\n if (storage) {\n this.storage = storage;\n } else if (typeof window !== 'undefined' && window.localStorage) {\n this.storage = window.localStorage;\n } else {\n // Fallback: in-memory storage for Node.js environments\n const store = new Map<string, string>();\n this.storage = {\n getItem: (key: string) => store.get(key) || null,\n setItem: (key: string, value: string) => { store.set(key, value); },\n removeItem: (key: string) => { store.delete(key); },\n };\n }\n }\n\n saveSession(session: AuthSession): void {\n this.storage.setItem(TOKEN_KEY, session.accessToken);\n this.storage.setItem(USER_KEY, JSON.stringify(session.user));\n }\n\n getSession(): AuthSession | null {\n const token = this.storage.getItem(TOKEN_KEY);\n const userStr = this.storage.getItem(USER_KEY);\n\n if (!token || !userStr) return null;\n\n try {\n const user = JSON.parse(userStr as string);\n return { accessToken: token as string, user };\n } catch {\n this.clearSession();\n return null;\n }\n }\n\n getAccessToken(): string | null {\n const token = this.storage.getItem(TOKEN_KEY);\n return typeof token === 'string' ? token : null;\n }\n\n setAccessToken(token: string): void {\n this.storage.setItem(TOKEN_KEY, token);\n }\n\n getUser(): UserSchema | null {\n const userStr = this.storage.getItem(USER_KEY);\n if (!userStr) return null;\n try {\n return JSON.parse(userStr as string);\n } catch {\n return null;\n }\n }\n\n setUser(user: UserSchema): void {\n this.storage.setItem(USER_KEY, JSON.stringify(user));\n }\n\n clearSession(): void {\n this.storage.removeItem(TOKEN_KEY);\n this.storage.removeItem(USER_KEY);\n }\n\n shouldAttemptRefresh(): boolean {\n // In persistent mode, we always have the token in storage\n // No need to refresh on page load\n return false;\n }\n}\n","/**\r\n * Token Manager for InsForge SDK\r\n * \r\n * A thin wrapper that delegates to the underlying SessionStorageStrategy.\r\n * This class maintains backward compatibility while using the Strategy Pattern internally.\r\n */\r\n\r\nimport type { UserSchema } from '@insforge/shared-schemas';\r\nimport type { AuthSession, TokenStorage } from '../types';\r\nimport {\r\n SessionStorageStrategy,\r\n LocalSessionStorage,\r\n} from './session-storage';\r\n\r\n/**\r\n * TokenManager - Manages session storage using the Strategy Pattern\r\n * \r\n * The actual storage implementation is delegated to a SessionStorageStrategy.\r\n * By default, uses LocalSessionStorage until a strategy is explicitly set\r\n * via setStrategy() during client initialization.\r\n */\r\nexport class TokenManager {\r\n private strategy: SessionStorageStrategy;\r\n\r\n /**\r\n * Create a new TokenManager\r\n * @param storage - Optional custom storage adapter (used for initial LocalSessionStorage)\r\n */\r\n constructor(storage?: TokenStorage) {\r\n // Default to persistent storage until capability discovery completes\r\n this.strategy = new LocalSessionStorage(storage);\r\n }\r\n\r\n /**\r\n * Set the storage strategy\r\n * Called after capability discovery to switch to the appropriate strategy\r\n */\r\n setStrategy(strategy: SessionStorageStrategy): void {\r\n // Migrate existing session data if switching strategies\r\n const existingSession = this.strategy.getSession();\r\n const previousId = this.strategy.strategyId;\r\n \r\n this.strategy = strategy;\r\n \r\n // If we had a session and are switching to a different strategy, migrate it\r\n if (existingSession && previousId !== strategy.strategyId) {\r\n strategy.saveSession(existingSession);\r\n }\r\n }\r\n\r\n /**\r\n * Get the current strategy identifier\r\n */\r\n getStrategyId(): string {\r\n return this.strategy.strategyId;\r\n }\r\n\r\n // --- Delegated Methods ---\r\n\r\n /**\r\n * Save session data\r\n */\r\n saveSession(session: AuthSession): void {\r\n this.strategy.saveSession(session);\r\n }\r\n\r\n /**\r\n * Get current session\r\n */\r\n getSession(): AuthSession | null {\r\n return this.strategy.getSession();\r\n }\r\n\r\n /**\r\n * Get access token\r\n */\r\n getAccessToken(): string | null {\r\n return this.strategy.getAccessToken();\r\n }\r\n\r\n /**\r\n * Update access token (e.g., after refresh)\r\n */\r\n setAccessToken(token: string): void {\r\n this.strategy.setAccessToken(token);\r\n }\r\n\r\n /**\r\n * Get user data\r\n */\r\n getUser(): UserSchema | null {\r\n return this.strategy.getUser();\r\n }\r\n\r\n /**\r\n * Update user data\r\n */\r\n setUser(user: UserSchema): void {\r\n this.strategy.setUser(user);\r\n }\r\n\r\n /**\r\n * Clear all session data\r\n */\r\n clearSession(): void {\r\n this.strategy.clearSession();\r\n }\r\n\r\n /**\r\n * Check if token refresh should be attempted\r\n * (e.g., on page reload in secure mode)\r\n */\r\n shouldAttemptRefresh(): boolean {\r\n return this.strategy.shouldAttemptRefresh();\r\n }\r\n}\r\n","/**\r\n * Database module using @supabase/postgrest-js\r\n * Complete replacement for custom QueryBuilder with full PostgREST features\r\n */\r\n\r\nimport { PostgrestClient } from '@supabase/postgrest-js';\r\nimport { HttpClient } from '../lib/http-client';\r\nimport { TokenManager } from '../lib/token-manager';\r\n\r\n\r\n/**\r\n * Custom fetch that transforms URLs and adds auth\r\n */\r\nfunction createInsForgePostgrestFetch(\r\n httpClient: HttpClient,\r\n tokenManager: TokenManager\r\n): typeof fetch {\r\n return async (input: RequestInfo | URL, init?: RequestInit): Promise<Response> => {\r\n const url = typeof input === 'string' ? input : input.toString();\r\n const urlObj = new URL(url);\r\n \r\n // Extract table name from pathname\r\n // postgrest-js sends: http://dummy/tablename?params\r\n // We need: http://localhost:7130/api/database/records/tablename?params\r\n const tableName = urlObj.pathname.slice(1); // Remove leading /\r\n \r\n // Build InsForge URL\r\n const insforgeUrl = `${httpClient.baseUrl}/api/database/records/${tableName}${urlObj.search}`;\r\n \r\n // Get auth token from TokenManager or HttpClient\r\n const token = tokenManager.getAccessToken();\r\n const httpHeaders = httpClient.getHeaders();\r\n const authToken = token || httpHeaders['Authorization']?.replace('Bearer ', '');\r\n \r\n // Prepare headers\r\n const headers = new Headers(init?.headers);\r\n if (authToken && !headers.has('Authorization')) {\r\n headers.set('Authorization', `Bearer ${authToken}`);\r\n }\r\n \r\n // Make the actual request using native fetch\r\n const response = await fetch(insforgeUrl, {\r\n ...init,\r\n headers\r\n });\r\n \r\n return response;\r\n };\r\n}\r\n\r\n/**\r\n * Database client using postgrest-js\r\n * Drop-in replacement with FULL PostgREST capabilities\r\n */\r\nexport class Database {\r\n private postgrest: PostgrestClient<any, any, any>;\r\n \r\n constructor(httpClient: HttpClient, tokenManager: TokenManager) {\r\n // Create postgrest client with custom fetch\r\n this.postgrest = new PostgrestClient<any, any, any>('http://dummy', {\r\n fetch: createInsForgePostgrestFetch(httpClient, tokenManager),\r\n headers: {}\r\n });\r\n }\r\n \r\n /**\r\n * Create a query builder for a table\r\n * \r\n * @example\r\n * // Basic query\r\n * const { data, error } = await client.database\r\n * .from('posts')\r\n * .select('*')\r\n * .eq('user_id', userId);\r\n * \r\n * // With count (Supabase style!)\r\n * const { data, error, count } = await client.database\r\n * .from('posts')\r\n * .select('*', { count: 'exact' })\r\n * .range(0, 9);\r\n * \r\n * // Just get count, no data\r\n * const { count } = await client.database\r\n * .from('posts')\r\n * .select('*', { count: 'exact', head: true });\r\n * \r\n * // Complex queries with OR\r\n * const { data } = await client.database\r\n * .from('posts')\r\n * .select('*, users!inner(*)')\r\n * .or('status.eq.active,status.eq.pending');\r\n * \r\n * // All features work:\r\n * - Nested selects\r\n * - Foreign key expansion \r\n * - OR/AND/NOT conditions\r\n * - Count with head\r\n * - Range pagination\r\n * - Upserts\r\n */\r\n from(table: string) {\r\n // Return postgrest query builder with all features\r\n return this.postgrest.from(table);\r\n }\r\n}","/**\n * Auth module for InsForge SDK\n * Uses shared schemas for type safety\n */\n\nimport { HttpClient } from '../lib/http-client';\nimport { TokenManager } from '../lib/token-manager';\nimport { SecureSessionStorage, LocalSessionStorage, AUTH_FLAG_COOKIE, TOKEN_KEY, USER_KEY } from '../lib/session-storage';\nimport { AuthSession, InsForgeError } from '../types';\nimport { Database } from './database-postgrest';\n\nimport type {\n CreateUserRequest,\n CreateUserResponse,\n CreateSessionRequest,\n CreateSessionResponse,\n GetCurrentSessionResponse,\n GetOauthUrlResponse,\n GetPublicAuthConfigResponse,\n OAuthProvidersSchema,\n UserIdSchema,\n EmailSchema,\n RoleSchema,\n SendVerificationEmailRequest,\n SendResetPasswordEmailRequest,\n ExchangeResetPasswordTokenRequest,\n VerifyEmailRequest,\n} from '@insforge/shared-schemas';\n\n/**\n * Dynamic profile type - represents flexible profile data from database\n * Fields can vary based on database schema configuration.\n * All fields are converted from snake_case (database) to camelCase (API)\n */\nexport type ProfileData = Record<string, any> & {\n id: string; // User ID (required)\n createdAt?: string; // PostgreSQL TIMESTAMPTZ\n updatedAt?: string; // PostgreSQL TIMESTAMPTZ\n};\n\n/**\n * Dynamic profile update type - for updating profile fields\n * Supports any fields that exist in the profile table\n */\nexport type UpdateProfileData = Partial<Record<string, any>>;\n\n/**\n * Convert database profile to include both snake_case and camelCase formats\n * Handles dynamic fields flexibly - automatically converts all snake_case keys to camelCase\n * \n * NOTE: Backward compatibility for <= v0.0.57\n * Both formats are returned to maintain compatibility with existing code.\n * For example: both created_at and createdAt are included in the result.\n */\nfunction convertDbProfileToCamelCase(dbProfile: Record<string, any>): ProfileData {\n const result: ProfileData = {\n id: dbProfile.id,\n };\n\n // Convert all fields - keep both snake_case and camelCase for backward compatibility (<= v0.0.57)\n Object.keys(dbProfile).forEach(key => {\n\n // Keep original field (snake_case) for backward compatibility (<= v0.0.57)\n result[key] = dbProfile[key];\n\n // Also add camelCase version if field contains underscore\n // e.g., created_at -> createdAt, avatar_url -> avatarUrl, etc.\n if (key.includes('_')) {\n const camelKey = key.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());\n result[camelKey] = dbProfile[key];\n }\n });\n\n return result;\n}\n\n/**\n * Convert camelCase profile data to database format (snake_case)\n * Handles dynamic fields flexibly - automatically converts all camelCase keys to snake_case\n */\nfunction convertCamelCaseToDbProfile(profile: UpdateProfileData): Record<string, any> {\n const dbProfile: Record<string, any> = {};\n\n Object.keys(profile).forEach(key => {\n if (profile[key] === undefined) return;\n\n // Convert camelCase to snake_case\n // e.g., avatarUrl -> avatar_url, firstName -> first_name\n const snakeKey = key.replace(/[A-Z]/g, letter => `_${letter.toLowerCase()}`);\n dbProfile[snakeKey] = profile[key];\n });\n\n return dbProfile;\n}\n\n/**\n * Check if current environment is a hosted auth environment\n * Returns true for:\n * - localhost with port 7130 (hosted auth app dev)\n * - https://*.insforge.app (hosted auth app production)\n */\nfunction isHostedAuthEnvironment(): boolean {\n if (typeof window === 'undefined') {\n return false;\n }\n\n const { hostname, port, protocol } = window.location;\n\n // Check for localhost:7130\n if (hostname === 'localhost' && port === '7130') {\n return true;\n }\n\n // Check for https://*.insforge.app\n if (protocol === 'https:' && hostname.endsWith('.insforge.app')) {\n return true;\n }\n\n return false;\n}\n\nexport class Auth {\n private database: Database;\n\n constructor(\n private http: HttpClient,\n private tokenManager: TokenManager\n ) {\n this.database = new Database(http, tokenManager);\n // Auto-detect OAuth callback parameters in the URL\n this.detectAuthCallback();\n }\n\n /**\n * Set the isAuthenticated cookie flag on the frontend domain\n * This is managed by SDK, not backend, to work in cross-origin scenarios\n */\n private setAuthenticatedCookie(): void {\n if (typeof document === 'undefined') return;\n // Set cookie with 7 days expiry, matching backend's refresh token lifetime\n const maxAge = 7 * 24 * 60 * 60; // 7 days in seconds\n document.cookie = `${AUTH_FLAG_COOKIE}=true; path=/; max-age=${maxAge}; SameSite=Lax`;\n }\n\n /**\n * Clear the isAuthenticated cookie flag from the frontend domain\n */\n private clearAuthenticatedCookie(): void {\n if (typeof document === 'undefined') return;\n document.cookie = `${AUTH_FLAG_COOKIE}=; path=/; max-age=0; SameSite=Lax`;\n }\n\n /**\n * Switch to SecureSessionStorage (cookie-based auth)\n * Called when backend returns sessionMode: 'secure'\n * @internal\n */\n _switchToSecureStorage(): void {\n if (this.tokenManager.getStrategyId() === 'secure') return;\n\n const currentSession = this.tokenManager.getSession();\n this.tokenManager.setStrategy(new SecureSessionStorage());\n\n // Clear localStorage (no longer needed)\n if (typeof localStorage !== 'undefined') {\n localStorage.removeItem(TOKEN_KEY);\n localStorage.removeItem(USER_KEY);\n }\n\n // Set SDK-managed cookie flag for page reload detection\n this.setAuthenticatedCookie();\n\n // Migrate session to new strategy (in-memory)\n if (currentSession) {\n this.tokenManager.saveSession(currentSession);\n }\n }\n\n /**\n * Switch to LocalSessionStorage (localStorage-based auth)\n * Called when cookie-based auth fails (fallback)\n * @internal\n */\n _switchToLocalStorage(): void {\n if (this.tokenManager.getStrategyId() === 'local') return;\n\n const currentSession = this.tokenManager.getSession();\n this.tokenManager.setStrategy(new LocalSessionStorage());\n\n // Clear SDK-managed cookie flag\n this.clearAuthenticatedCookie();\n\n // Migrate session to new strategy\n if (currentSession) {\n this.tokenManager.saveSession(currentSession);\n }\n }\n\n /**\n * Detect storage strategy based on backend response\n * @param sessionMode - The sessionMode returned by backend ('secure' or undefined)\n * @internal\n */\n private _detectStorageFromResponse(sessionMode?: string): void {\n if (sessionMode === 'secure') {\n this._switchToSecureStorage();\n }\n // Otherwise keep current strategy (LocalSessionStorage)\n }\n\n /**\n * Automatically detect and handle OAuth callback parameters in the URL\n * This runs on initialization to seamlessly complete the OAuth flow\n * Matches the backend's OAuth callback response (backend/src/api/routes/auth.ts:540-544)\n */\n detectAuthCallback(): void {\n // Only run in browser environment\n if (typeof window === 'undefined') return;\n\n try {\n const params = new URLSearchParams(window.location.search);\n\n // Backend returns: access_token, user_id, email, name (optional), session_mode\n const accessToken = params.get('access_token');\n const userId = params.get('user_id');\n const email = params.get('email');\n const name = params.get('name');\n const sessionMode = params.get('session_mode');\n\n // Check if we have OAuth callback parameters\n if (accessToken && userId && email) {\n // Detect backend storage mode from URL parameter FIRST (before saving session)\n this._detectStorageFromResponse(sessionMode || undefined);\n\n // Create session with the data from backend\n const session: AuthSession = {\n accessToken,\n user: {\n id: userId,\n email: email,\n name: name || '',\n // These fields are not provided by backend OAuth callback\n // They'll be populated when calling getCurrentUser()\n emailVerified: false,\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString(),\n } as any,\n };\n\n // Save session and set auth token\n this.tokenManager.saveSession(session);\n this.http.setAuthToken(accessToken);\n\n // Clean up the URL to remove sensitive parameters\n const url = new URL(window.location.href);\n url.searchParams.delete('access_token');\n url.searchParams.delete('user_id');\n url.searchParams.delete('email');\n url.searchParams.delete('name');\n url.searchParams.delete('session_mode');\n\n // Also handle error case from backend (line 581)\n if (params.has('error')) {\n url.searchParams.delete('error');\n }\n\n // Replace URL without adding to browser history\n window.history.replaceState({}, document.title, url.toString());\n }\n } catch (error) {\n // Silently continue - don't break initialization\n console.debug('OAuth callback detection skipped:', error);\n }\n }\n\n /**\n * Sign up a new user\n */\n async signUp(request: CreateUserRequest): Promise<{\n data: CreateUserResponse | null;\n error: InsForgeError | null;\n }> {\n try {\n const response = await this.http.post<CreateUserResponse>('/api/auth/users', request);\n\n // Detect storage mode from backend response FIRST (before saving session)\n // This ensures session is saved to the correct storage strategy\n const sessionMode = (response as any).sessionMode as string | undefined;\n this._detectStorageFromResponse(sessionMode);\n\n // Save session internally only if both accessToken and user exist\n if (response.accessToken && response.user) {\n const session: AuthSession = {\n accessToken: response.accessToken,\n user: response.user,\n };\n if (!isHostedAuthEnvironment()) {\n this.tokenManager.saveSession(session);\n }\n this.http.setAuthToken(response.accessToken);\n }\n\n return {\n data: response,\n error: null\n };\n } catch (error) {\n // Pass through API errors unchanged\n if (error instanceof InsForgeError) {\n return { data: null, error };\n }\n\n // Generic fallback for unexpected errors\n return {\n data: null,\n error: new InsForgeError(\n error instanceof Error ? error.message : 'An unexpected error occurred during sign up',\n 500,\n 'UNEXPECTED_ERROR'\n )\n };\n }\n }\n\n /**\n * Sign in with email and password\n */\n async signInWithPassword(request: CreateSessionRequest): Promise<{\n data: CreateSessionResponse | null;\n error: InsForgeError | null;\n }> {\n try {\n const response = await this.http.post<CreateSessionResponse>('/api/auth/sessions', request);\n\n // Detect storage mode from backend response FIRST (before saving session)\n const sessionMode = (response as any).sessionMode as string | undefined;\n this._detectStorageFromResponse(sessionMode);\n\n // Save session internally\n const session: AuthSession = {\n accessToken: response.accessToken || '',\n user: response.user || {\n id: '',\n email: '',\n name: '',\n emailVerified: false,\n createdAt: '',\n updatedAt: '',\n },\n };\n\n if (!isHostedAuthEnvironment()) {\n this.tokenManager.saveSession(session);\n }\n this.http.setAuthToken(response.accessToken || '');\n\n return {\n data: response,\n error: null\n };\n } catch (error) {\n // Pass through API errors unchanged\n if (error instanceof InsForgeError) {\n return { data: null, error };\n }\n\n // Generic fallback for unexpected errors\n return {\n data: null,\n error: new InsForgeError(\n 'An unexpected error occurred during sign in',\n 500,\n 'UNEXPECTED_ERROR'\n )\n };\n }\n }\n\n /**\n * Sign in with OAuth provider\n */\n async signInWithOAuth(options: {\n provider: OAuthProvidersSchema;\n redirectTo?: string;\n skipBrowserRedirect?: boolean;\n }): Promise<{\n data: { url?: string; provider?: string };\n error: InsForgeError | null;\n }> {\n try {\n const { provider, redirectTo, skipBrowserRedirect } = options;\n\n const params = redirectTo\n ? { redirect_uri: redirectTo }\n : undefined;\n\n const endpoint = `/api/auth/oauth/${provider}`;\n const response = await this.http.get<GetOauthUrlResponse>(endpoint, { params });\n\n // Automatically redirect in browser unless told not to\n if (typeof window !== 'undefined' && !skipBrowserRedirect) {\n window.location.href = response.authUrl;\n return { data: {}, error: null };\n }\n\n return {\n data: {\n url: response.authUrl,\n provider\n },\n error: null\n };\n } catch (error) {\n // Pass through API errors unchanged\n if (error instanceof InsForgeError) {\n return { data: {}, error };\n }\n\n // Generic fallback for unexpected errors\n return {\n data: {},\n error: new InsForgeError(\n 'An unexpected error occurred during OAuth initialization',\n 500,\n 'UNEXPECTED_ERROR'\n )\n };\n }\n }\n\n /**\n * Sign out the current user\n * In modern mode, also calls backend to clear the refresh token cookie\n */\n async signOut(): Promise<{ error: InsForgeError | null }> {\n try {\n // If using secure storage, call backend to clear refresh token cookie\n if (this.tokenManager.getStrategyId() === 'secure') {\n try {\n await this.http.post('/api/auth/logout');\n } catch {\n // Ignore errors from logout endpoint - still clear local session\n }\n }\n\n this.tokenManager.clearSession();\n this.http.setAuthToken(null);\n\n // Clear SDK-managed isAuthenticated cookie (frontend domain)\n this.clearAuthenticatedCookie();\n\n return { error: null };\n } catch (error) {\n return {\n error: new InsForgeError(\n 'Failed to sign out',\n 500,\n 'SIGNOUT_ERROR'\n )\n };\n }\n }\n\n /**\n * Refresh the access token using the httpOnly refresh token cookie\n * Only works when backend supports secure session storage (httpOnly cookies)\n * \n * @returns New access token or throws an error\n */\n async refreshToken(): Promise<string> {\n try {\n const response = await this.http.post<{ accessToken: string; user?: any; sessionMode?: string }>(\n '/api/auth/refresh'\n );\n\n if (response.accessToken) {\n // Detect/confirm storage mode from backend response\n // This ensures we stay in secure mode after refresh\n this._detectStorageFromResponse(response.sessionMode);\n\n // Update token manager with new token\n this.tokenManager.setAccessToken(response.accessToken);\n this.http.setAuthToken(response.accessToken);\n\n // Update user data if provided\n if (response.user) {\n this.tokenManager.setUser(response.user);\n }\n\n return response.accessToken;\n }\n\n throw new InsForgeError(\n 'No access token in refresh response',\n 500,\n 'REFRESH_FAILED'\n );\n } catch (error) {\n if (error instanceof InsForgeError) {\n // Only clear session on auth-related errors\n if (error.statusCode === 401 || error.statusCode === 403) {\n this.tokenManager.clearSession();\n this.http.setAuthToken(null);\n // Clear SDK-managed cookie on auth failure\n this.clearAuthenticatedCookie();\n }\n throw error;\n }\n\n throw new InsForgeError(\n 'Token refresh failed',\n 500,\n 'REFRESH_FAILED'\n );\n }\n }\n\n\n /**\n * Get all public authentication configuration (OAuth + Email)\n * Returns both OAuth providers and email authentication settings in one request\n * This is a public endpoint that doesn't require authentication\n * \n * @returns Complete public authentication configuration including OAuth providers and email auth settings\n * \n * @example\n * ```ts\n * const { data, error } = await insforge.auth.getPublicAuthConfig();\n * if (data) {\n * console.log(`OAuth providers: ${data.oauth.data.length}`);\n * console.log(`Password min length: ${data.email.passwordMinLength}`);\n * }\n * ```\n */\n async getPublicAuthConfig(): Promise<{\n data: GetPublicAuthConfigResponse | null;\n error: InsForgeError | null;\n }> {\n try {\n const response = await this.http.get<GetPublicAuthConfigResponse>('/api/auth/public-config');\n\n return {\n data: response,\n error: null\n };\n } catch (error) {\n // Pass through API errors unchanged\n if (error instanceof InsForgeError) {\n return { data: null, error };\n }\n\n // Generic fallback for unexpected errors\n return {\n data: null,\n error: new InsForgeError(\n 'An unexpected error occurred while fetching public authentication configuration',\n 500,\n 'UNEXPECTED_ERROR'\n )\n };\n }\n }\n\n\n /**\n * Get the current user with full profile information\n * Returns both auth info (id, email, role) and profile data (dynamic fields from users table)\n * \n * In secure session mode (httpOnly cookie), this method will automatically attempt\n * to refresh the session if no access token is available (e.g., after page reload).\n */\n async getCurrentUser(): Promise<{\n data: {\n user: {\n id: UserIdSchema;\n email: EmailSchema;\n role: RoleSchema;\n };\n profile: ProfileData | null;\n } | null;\n error: any | null;\n }> {\n try {\n // Check if we have a token\n // Use getAccessToken() instead of getSession() to avoid requiring user data\n // This decouples token availability from cached user data\n let accessToken = this.tokenManager.getAccessToken();\n\n // In secure mode, if no token in memory but auth cookie exists, try to refresh\n // This handles page reload scenario where access token was in memory only\n if (!accessToken && this.tokenManager.shouldAttemptRefresh()) {\n try {\n accessToken = await this.refreshToken();\n } catch (error) {\n if (error instanceof InsForgeError && (error.statusCode === 401 || error.statusCode === 403)) {\n return { data: null, error: error };\n }\n return { data: null, error: error instanceof InsForgeError ? error : new InsForgeError('Token refresh failed', 500, 'REFRESH_FAILED') };\n }\n }\n\n if (!accessToken) {\n return { data: null, error: null };\n }\n\n // Call the API for auth info\n this.http.setAuthToken(accessToken);\n const authResponse = await this.http.get<GetCurrentSessionResponse>('/api/auth/sessions/current');\n\n // Get the user's profile using query builder\n const { data: profile, error: profileError } = await this.database\n .from('users')\n .select('*')\n .eq('id', authResponse.user.id)\n .single();\n\n // For database errors, return PostgrestError directly\n if (profileError && (profileError as any).code !== 'PGRST116') { // PGRST116 = not found\n return { data: null, error: profileError };\n }\n\n return {\n data: {\n user: authResponse.user,\n profile: profile ? convertDbProfileToCamelCase(profile) : null\n },\n error: null\n };\n } catch (error) {\n // If unauthorized, clear session\n if (error instanceof InsForgeError && error.statusCode === 401) {\n await this.signOut();\n return { data: null, error: null };\n }\n\n // Pass through all other errors unchanged\n if (error instanceof InsForgeError) {\n return { data: null, error };\n }\n\n // Generic fallback for unexpected errors\n return {\n data: null,\n error: new InsForgeError(\n 'An unexpected error occurred while fetching user',\n 500,\n 'UNEXPECTED_ERROR'\n )\n };\n }\n }\n\n /**\n * Get any user's profile by ID\n * Returns profile information from the users table (dynamic fields)\n */\n async getProfile(userId: string): Promise<{\n data: ProfileData | null;\n error: any | null;\n }> {\n const { data, error } = await this.database\n .from('users')\n .select('*')\n .eq('id', userId)\n .single();\n\n // Handle not found as null, not error\n if (error && (error as any).code === 'PGRST116') {\n return { data: null, error: null };\n }\n\n // Convert database format to camelCase format\n if (data) {\n return { data: convertDbProfileToCamelCase(data), error: null };\n }\n\n // Return PostgrestError directly for database operations\n return { data: null, error };\n }\n\n /**\n * Get the current session (only session data, no API call)\n * Returns the stored JWT token and basic user info from local storage\n */\n getCurrentSession(): {\n data: { session: AuthSession | null };\n error: InsForgeError | null;\n } {\n try {\n const session = this.tokenManager.getSession();\n\n if (session?.accessToken) {\n this.http.setAuthToken(session.accessToken);\n return { data: { session }, error: null };\n }\n\n return { data: { session: null }, error: null };\n } catch (error) {\n // Pass through API errors unchanged\n if (error instanceof InsForgeError) {\n return { data: { session: null }, error };\n }\n\n // Generic fallback for unexpected errors\n return {\n data: { session: null },\n error: new InsForgeError(\n 'An unexpected error occurred while getting session',\n 500,\n 'UNEXPECTED_ERROR'\n )\n };\n }\n }\n\n /**\n * Set/Update the current user's profile\n * Updates profile information in the users table (supports any dynamic fields)\n */\n async setProfile(profile: UpdateProfileData): Promise<{\n data: ProfileData | null;\n error: any | null;\n }> {\n // Get current session to get user ID\n const session = this.tokenManager.getSession();\n if (!session?.accessToken) {\n return {\n data: null,\n error: new InsForgeError(\n 'No authenticated user found',\n 401,\n 'UNAUTHENTICATED'\n )\n };\n }\n\n // If no user ID in session (edge function scenario), fetch it\n if (!session.user?.id) {\n const { data, error } = await this.getCurrentUser();\n if (error) {\n return { data: null, error };\n }\n if (data?.user) {\n // Update session with minimal user info\n session.user = {\n id: data.user.id,\n email: data.user.email,\n name: '',\n emailVerified: false,\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString(),\n };\n this.tokenManager.saveSession(session);\n }\n }\n\n // Convert camelCase format to database format (snake_case)\n const dbProfile = convertCamelCaseToDbProfile(profile);\n\n // Update the profile using query builder\n const { data, error } = await this.database\n .from('users')\n .update(dbProfile)\n .eq('id', session.user.id)\n .select()\n .single();\n\n // Convert database format back to camelCase format\n if (data) {\n return { data: convertDbProfileToCamelCase(data), error: null };\n }\n\n // Return PostgrestError directly for database operations\n return { data: null, error };\n }\n\n /**\n * Send email verification (code or link based on config)\n *\n * Send email verification using the method configured in auth settings (verifyEmailMethod).\n * When method is 'code', sends a 6-digit numeric code. When method is 'link', sends a magic link.\n * Prevents user enumeration by returning success even if email doesn't exist.\n */\n async sendVerificationEmail(request: SendVerificationEmailRequest): Promise<{\n data: { success: boolean; message: string } | null;\n error: InsForgeError | null;\n }> {\n try {\n const response = await this.http.post<{ success: boolean; message: string }>(\n '/api/auth/email/send-verification',\n request\n );\n\n return {\n data: response,\n error: null\n };\n } catch (error) {\n // Pass through API errors unchanged\n if (error instanceof InsForgeError) {\n return { data: null, error };\n }\n\n // Generic fallback for unexpected errors\n return {\n data: null,\n error: new InsForgeError(\n 'An unexpected error occurred while sending verification code',\n 500,\n 'UNEXPECTED_ERROR'\n )\n };\n }\n }\n\n /**\n * Send password reset (code or link based on config)\n *\n * Send password reset email using the method configured in auth settings (resetPasswordMethod).\n * When method is 'code', sends a 6-digit numeric code for two-step flow.\n * When method is 'link', sends a magic link.\n * Prevents user enumeration by returning success even if email doesn't exist.\n */\n async sendResetPasswordEmail(request: SendResetPasswordEmailRequest): Promise<{\n data: { success: boolean; message: string } | null;\n error: InsForgeError | null;\n }> {\n try {\n const response = await this.http.post<{ success: boolean; message: string }>(\n '/api/auth/email/send-reset-password',\n request\n );\n\n return {\n data: response,\n error: null\n };\n } catch (error) {\n // Pass through API errors unchanged\n if (error instanceof InsForgeError) {\n return { data: null, error };\n }\n\n // Generic fallback for unexpected errors\n return {\n data: null,\n error: new InsForgeError(\n 'An unexpected error occurred while sending password reset code',\n 500,\n 'UNEXPECTED_ERROR'\n )\n };\n }\n }\n\n /**\n * Exchange reset password code for reset token\n *\n * Step 1 of two-step password reset flow (only used when resetPasswordMethod is 'code'):\n * 1. Verify the 6-digit code sent to user's email\n * 2. Return a reset token that can be used to actually reset the password\n *\n * This endpoint is not used when resetPasswordMethod is 'link' (magic link flow is direct).\n */\n async exchangeResetPasswordToken(request: ExchangeResetPasswordTokenRequest): Promise<{\n data: { token: string; expiresAt: string } | null;\n error: InsForgeError | null;\n }> {\n try {\n const response = await this.http.post<{ token: string; expiresAt: string }>(\n '/api/auth/email/exchange-reset-password-token',\n request\n );\n\n return {\n data: response,\n error: null\n };\n } catch (error) {\n // Pass through API errors unchanged\n if (error instanceof InsForgeError) {\n return { data: null, error };\n }\n\n // Generic fallback for unexpected errors\n return {\n data: null,\n error: new InsForgeError(\n 'An unexpected error occurred while verifying reset code',\n 500,\n 'UNEXPECTED_ERROR'\n )\n };\n }\n }\n\n /**\n * Reset password with token\n *\n * Reset user password with a token. The token can be:\n * - Magic link token (64-character hex token from send-reset-password when method is 'link')\n * - Reset token (from exchange-reset-password-token after code verification when method is 'code')\n *\n * Both token types use RESET_PASSWORD purpose and are verified the same way.\n *\n * Flow summary:\n * - Code method: send-reset-password → exchange-reset-password-token → reset-password (with resetToken)\n * - Link method: send-reset-password → reset-password (with link token directly)\n */\n async resetPassword(request: { newPassword: string; otp: string }): Promise<{\n data: { message: string; redirectTo?: string } | null;\n error: InsForgeError | null;\n }> {\n try {\n const response = await this.http.post<{ message: string; redirectTo?: string }>(\n '/api/auth/email/reset-password',\n request\n );\n\n return {\n data: response,\n error: null\n };\n } catch (error) {\n // Pass through API errors unchanged\n if (error instanceof InsForgeError) {\n return { data: null, error };\n }\n\n // Generic fallback for unexpected errors\n return {\n data: null,\n error: new InsForgeError(\n 'An unexpected error occurred while resetting password',\n 500,\n 'UNEXPECTED_ERROR'\n )\n };\n }\n }\n\n /**\n * Verify email with code or link\n *\n * Verify email address using the method configured in auth settings (verifyEmailMethod):\n * - Code verification: Provide both `email` and `otp` (6-digit numeric code)\n * - Link verification: Provide only `otp` (64-character hex token from magic link)\n *\n * Successfully verified users will receive a session token.\n *\n * The email verification link sent to users always points to the backend API endpoint.\n * If `verifyEmailRedirectTo` is configured, the backend will redirect to that URL after successful verification.\n * Otherwise, a default success page is displayed.\n */\n async verifyEmail(request: VerifyEmailRequest): Promise<{\n data: { accessToken: string; user?: any; redirectTo?: string } | null;\n error: InsForgeError | null;\n }> {\n try {\n const response = await this.http.post<{ accessToken: string; user?: any; redirectTo?: string; sessionMode?: string }>(\n '/api/auth/email/verify',\n request\n );\n\n // Detect storage mode from backend response FIRST (before saving session)\n const sessionMode = (response as any).sessionMode as string | undefined;\n this._detectStorageFromResponse(sessionMode);\n\n // Save session if we got a token\n if (response.accessToken) {\n const session: AuthSession = {\n accessToken: response.accessToken,\n user: response.user || {} as any,\n };\n this.tokenManager.saveSession(session);\n this.http.setAuthToken(response.accessToken);\n }\n\n return {\n data: response,\n error: null\n };\n } catch (error) {\n // Pass through API errors unchanged\n if (error instanceof InsForgeError) {\n return { data: null, error };\n }\n\n // Generic fallback for unexpected errors\n return {\n data: null,\n error: new InsForgeError(\n 'An unexpected error occurred while verifying email',\n 500,\n 'UNEXPECTED_ERROR'\n )\n };\n }\n }\n}","/**\r\n * Storage module for InsForge SDK\r\n * Handles file uploads, downloads, and bucket management\r\n */\r\n\r\nimport { HttpClient } from '../lib/http-client';\r\nimport { InsForgeError } from '../types';\r\nimport type { \r\n StorageFileSchema,\r\n ListObjectsResponseSchema\r\n} from '@insforge/shared-schemas';\r\n\r\nexport interface StorageResponse<T> {\r\n data: T | null;\r\n error: InsForgeError | null;\r\n}\r\n\r\ninterface UploadStrategy {\r\n method: 'direct' | 'presigned';\r\n uploadUrl: string;\r\n fields?: Record<string, string>;\r\n key: string;\r\n confirmRequired: boolean;\r\n confirmUrl?: string;\r\n expiresAt?: Date;\r\n}\r\n\r\ninterface DownloadStrategy {\r\n method: 'direct' | 'presigned';\r\n url: string;\r\n expiresAt?: Date;\r\n}\r\n\r\n/**\r\n * Storage bucket operations\r\n */\r\nexport class StorageBucket {\r\n constructor(\r\n private bucketName: string,\r\n private http: HttpClient\r\n ) {}\r\n\r\n /**\r\n * Upload a file with a specific key\r\n * Uses the upload strategy from backend (direct or presigned)\r\n * @param path - The object key/path\r\n * @param file - File or Blob to upload\r\n */\r\n async upload(\r\n path: string,\r\n file: File | Blob\r\n ): Promise<StorageResponse<StorageFileSchema>> {\r\n try {\r\n // Get upload strategy from backend - this is required\r\n const strategyResponse = await this.http.post<UploadStrategy>(\r\n `/api/storage/buckets/${this.bucketName}/upload-strategy`,\r\n {\r\n filename: path,\r\n contentType: file.type || 'application/octet-stream',\r\n size: file.size\r\n }\r\n );\r\n\r\n // Use presigned URL if available\r\n if (strategyResponse.method === 'presigned') {\r\n return await this.uploadWithPresignedUrl(strategyResponse, file);\r\n }\r\n\r\n // Use direct upload if strategy says so\r\n if (strategyResponse.method === 'direct') {\r\n const formData = new FormData();\r\n formData.append('file', file);\r\n\r\n const response = await this.http.request<StorageFileSchema>(\r\n 'PUT',\r\n `/api/storage/buckets/${this.bucketName}/objects/${encodeURIComponent(path)}`,\r\n {\r\n body: formData as any,\r\n headers: {\r\n // Don't set Content-Type, let browser set multipart boundary\r\n }\r\n }\r\n );\r\n\r\n return { data: response, error: null };\r\n }\r\n\r\n throw new InsForgeError(\r\n `Unsupported upload method: ${strategyResponse.method}`,\r\n 500,\r\n 'STORAGE_ERROR'\r\n );\r\n } catch (error) {\r\n return { \r\n data: null, \r\n error: error instanceof InsForgeError ? error : new InsForgeError(\r\n 'Upload failed',\r\n 500,\r\n 'STORAGE_ERROR'\r\n )\r\n };\r\n }\r\n }\r\n\r\n /**\r\n * Upload a file with auto-generated key\r\n * Uses the upload strategy from backend (direct or presigned)\r\n * @param file - File or Blob to upload\r\n */\r\n async uploadAuto(\r\n file: File | Blob\r\n ): Promise<StorageResponse<StorageFileSchema>> {\r\n try {\r\n const filename = file instanceof File ? file.name : 'file';\r\n \r\n // Get upload strategy from backend - this is required\r\n const strategyResponse = await this.http.post<UploadStrategy>(\r\n `/api/storage/buckets/${this.bucketName}/upload-strategy`,\r\n {\r\n filename,\r\n contentType: file.type || 'application/octet-stream',\r\n size: file.size\r\n }\r\n );\r\n\r\n // Use presigned URL if available\r\n if (strategyResponse.method === 'presigned') {\r\n return await this.uploadWithPresignedUrl(strategyResponse, file);\r\n }\r\n\r\n // Use direct upload if strategy says so\r\n if (strategyResponse.method === 'direct') {\r\n const formData = new FormData();\r\n formData.append('file', file);\r\n\r\n const response = await this.http.request<StorageFileSchema>(\r\n 'POST',\r\n `/api/storage/buckets/${this.bucketName}/objects`,\r\n {\r\n body: formData as any,\r\n headers: {\r\n // Don't set Content-Type, let browser set multipart boundary\r\n }\r\n }\r\n );\r\n\r\n return { data: response, error: null };\r\n }\r\n\r\n throw new InsForgeError(\r\n `Unsupported upload method: ${strategyResponse.method}`,\r\n 500,\r\n 'STORAGE_ERROR'\r\n );\r\n } catch (error) {\r\n return { \r\n data: null, \r\n error: error instanceof InsForgeError ? error : new InsForgeError(\r\n 'Upload failed',\r\n 500,\r\n 'STORAGE_ERROR'\r\n )\r\n };\r\n }\r\n }\r\n\r\n /**\r\n * Internal method to handle presigned URL uploads\r\n */\r\n private async uploadWithPresignedUrl(\r\n strategy: UploadStrategy,\r\n file: File | Blob\r\n ): Promise<StorageResponse<StorageFileSchema>> {\r\n try {\r\n // Upload to presigned URL (e.g., S3)\r\n const formData = new FormData();\r\n \r\n // Add all fields from the presigned URL\r\n if (strategy.fields) {\r\n Object.entries(strategy.fields).forEach(([key, value]) => {\r\n formData.append(key, value);\r\n });\r\n }\r\n \r\n // File must be the last field for S3\r\n formData.append('file', file);\r\n\r\n const uploadResponse = await fetch(strategy.uploadUrl, {\r\n method: 'POST',\r\n body: formData\r\n });\r\n\r\n if (!uploadResponse.ok) {\r\n throw new InsForgeError(\r\n `Upload to storage failed: ${uploadResponse.statusText}`,\r\n uploadResponse.status,\r\n 'STORAGE_ERROR'\r\n );\r\n }\r\n\r\n // Confirm upload with backend if required\r\n if (strategy.confirmRequired && strategy.confirmUrl) {\r\n const confirmResponse = await this.http.post<StorageFileSchema>(\r\n strategy.confirmUrl,\r\n {\r\n size: file.size,\r\n contentType: file.type || 'application/octet-stream'\r\n }\r\n );\r\n\r\n return { data: confirmResponse, error: null };\r\n }\r\n\r\n // If no confirmation required, return basic file info\r\n return {\r\n data: {\r\n key: strategy.key,\r\n bucket: this.bucketName,\r\n size: file.size,\r\n mimeType: file.type || 'application/octet-stream',\r\n uploadedAt: new Date().toISOString(),\r\n url: this.getPublicUrl(strategy.key)\r\n } as StorageFileSchema,\r\n error: null\r\n };\r\n } catch (error) {\r\n throw error instanceof InsForgeError ? error : new InsForgeError(\r\n 'Presigned upload failed',\r\n 500,\r\n 'STORAGE_ERROR'\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Download a file\r\n * Uses the download strategy from backend (direct or presigned)\r\n * @param path - The object key/path\r\n * Returns the file as a Blob\r\n */\r\n async download(path: string): Promise<{ data: Blob | null; error: InsForgeError | null }> {\r\n try {\r\n // Get download strategy from backend - this is required\r\n const strategyResponse = await this.http.post<DownloadStrategy>(\r\n `/api/storage/buckets/${this.bucketName}/objects/${encodeURIComponent(path)}/download-strategy`,\r\n { expiresIn: 3600 }\r\n );\r\n\r\n // Use URL from strategy\r\n const downloadUrl = strategyResponse.url;\r\n \r\n // Download from the URL\r\n const headers: HeadersInit = {};\r\n \r\n // Only add auth header for direct downloads (not presigned URLs)\r\n if (strategyResponse.method === 'direct') {\r\n Object.assign(headers, this.http.getHeaders());\r\n }\r\n \r\n const response = await fetch(downloadUrl, {\r\n method: 'GET',\r\n headers\r\n });\r\n\r\n if (!response.ok) {\r\n try {\r\n const error = await response.json();\r\n throw InsForgeError.fromApiError(error);\r\n } catch {\r\n throw new InsForgeError(\r\n `Download failed: ${response.statusText}`,\r\n response.status,\r\n 'STORAGE_ERROR'\r\n );\r\n }\r\n }\r\n\r\n const blob = await response.blob();\r\n return { data: blob, error: null };\r\n } catch (error) {\r\n return { \r\n data: null, \r\n error: error instanceof InsForgeError ? error : new InsForgeError(\r\n 'Download failed',\r\n 500,\r\n 'STORAGE_ERROR'\r\n )\r\n };\r\n }\r\n }\r\n\r\n /**\r\n * Get public URL for a file\r\n * @param path - The object key/path\r\n */\r\n getPublicUrl(path: string): string {\r\n return `${this.http.baseUrl}/api/storage/buckets/${this.bucketName}/objects/${encodeURIComponent(path)}`;\r\n }\r\n\r\n /**\r\n * List objects in the bucket\r\n * @param prefix - Filter by key prefix\r\n * @param search - Search in file names\r\n * @param limit - Maximum number of results (default: 100, max: 1000)\r\n * @param offset - Number of results to skip\r\n */\r\n async list(options?: {\r\n prefix?: string;\r\n search?: string;\r\n limit?: number;\r\n offset?: number;\r\n }): Promise<StorageResponse<ListObjectsResponseSchema>> {\r\n try {\r\n const params: Record<string, string> = {};\r\n \r\n if (options?.prefix) params.prefix = options.prefix;\r\n if (options?.search) params.search = options.search;\r\n if (options?.limit) params.limit = options.limit.toString();\r\n if (options?.offset) params.offset = options.offset.toString();\r\n\r\n const response = await this.http.get<ListObjectsResponseSchema>(\r\n `/api/storage/buckets/${this.bucketName}/objects`,\r\n { params }\r\n );\r\n\r\n return { data: response, error: null };\r\n } catch (error) {\r\n return { \r\n data: null, \r\n error: error instanceof InsForgeError ? error : new InsForgeError(\r\n 'List failed',\r\n 500,\r\n 'STORAGE_ERROR'\r\n )\r\n };\r\n }\r\n }\r\n\r\n /**\r\n * Delete a file\r\n * @param path - The object key/path\r\n */\r\n async remove(path: string): Promise<StorageResponse<{ message: string }>> {\r\n try {\r\n const response = await this.http.delete<{ message: string }>(\r\n `/api/storage/buckets/${this.bucketName}/objects/${encodeURIComponent(path)}`\r\n );\r\n\r\n return { data: response, error: null };\r\n } catch (error) {\r\n return { \r\n data: null, \r\n error: error instanceof InsForgeError ? error : new InsForgeError(\r\n 'Delete failed',\r\n 500,\r\n 'STORAGE_ERROR'\r\n )\r\n };\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Storage module for file operations\r\n */\r\nexport class Storage {\r\n constructor(private http: HttpClient) {}\r\n\r\n /**\r\n * Get a bucket instance for operations\r\n * @param bucketName - Name of the bucket\r\n */\r\n from(bucketName: string): StorageBucket {\r\n return new StorageBucket(bucketName, this.http);\r\n }\r\n}","/**\r\n * AI Module for Insforge SDK\r\n * Response format roughly matches OpenAI SDK for compatibility\r\n *\r\n * The backend handles all the complexity of different AI providers\r\n * and returns a unified format. This SDK transforms responses to match OpenAI-like format.\r\n */\r\n\r\nimport { HttpClient } from \"../lib/http-client\";\r\nimport {\r\n ChatCompletionRequest,\r\n ChatCompletionResponse,\r\n ImageGenerationRequest,\r\n ImageGenerationResponse,\r\n} from \"@insforge/shared-schemas\";\r\n\r\nexport class AI {\r\n public readonly chat: Chat;\r\n public readonly images: Images;\r\n\r\n constructor(private http: HttpClient) {\r\n this.chat = new Chat(http);\r\n this.images = new Images(http);\r\n }\r\n}\r\n\r\nclass Chat {\r\n public readonly completions: ChatCompletions;\r\n\r\n constructor(http: HttpClient) {\r\n this.completions = new ChatCompletions(http);\r\n }\r\n}\r\n\r\nclass ChatCompletions {\r\n constructor(private http: HttpClient) {}\r\n\r\n /**\r\n * Create a chat completion - OpenAI-like response format\r\n *\r\n * @example\r\n * ```typescript\r\n * // Non-streaming\r\n * const completion = await client.ai.chat.completions.create({\r\n * model: 'gpt-4',\r\n * messages: [{ role: 'user', content: 'Hello!' }]\r\n * });\r\n * console.log(completion.choices[0].message.content);\r\n *\r\n * // With images\r\n * const response = await client.ai.chat.completions.create({\r\n * model: 'gpt-4-vision',\r\n * messages: [{\r\n * role: 'user',\r\n * content: 'What is in this image?',\r\n * images: [{ url: 'https://example.com/image.jpg' }]\r\n * }]\r\n * });\r\n *\r\n * // Streaming - returns async iterable\r\n * const stream = await client.ai.chat.completions.create({\r\n * model: 'gpt-4',\r\n * messages: [{ role: 'user', content: 'Tell me a story' }],\r\n * stream: true\r\n * });\r\n *\r\n * for await (const chunk of stream) {\r\n * if (chunk.choices[0]?.delta?.content) {\r\n * process.stdout.write(chunk.choices[0].delta.content);\r\n * }\r\n * }\r\n * ```\r\n */\r\n async create(params: ChatCompletionRequest): Promise<any> {\r\n // Backend already expects camelCase, no transformation needed\r\n const backendParams = {\r\n model: params.model,\r\n messages: params.messages,\r\n temperature: params.temperature,\r\n maxTokens: params.maxTokens,\r\n topP: params.topP,\r\n stream: params.stream,\r\n };\r\n\r\n // For streaming, return an async iterable that yields OpenAI-like chunks\r\n if (params.stream) {\r\n const headers = this.http.getHeaders();\r\n headers[\"Content-Type\"] = \"application/json\";\r\n\r\n const response = await this.http.fetch(\r\n `${this.http.baseUrl}/api/ai/chat/completion`,\r\n {\r\n method: \"POST\",\r\n headers,\r\n body: JSON.stringify(backendParams),\r\n }\r\n );\r\n\r\n if (!response.ok) {\r\n const error = await response.json();\r\n throw new Error(error.error || \"Stream request failed\");\r\n }\r\n\r\n // Return async iterable that parses SSE and transforms to OpenAI-like format\r\n return this.parseSSEStream(response, params.model);\r\n }\r\n\r\n // Non-streaming: transform response to OpenAI-like format\r\n const response: ChatCompletionResponse = await this.http.post(\r\n \"/api/ai/chat/completion\",\r\n backendParams\r\n );\r\n\r\n // Transform to OpenAI-like format\r\n const content = response.text || \"\";\r\n\r\n return {\r\n id: `chatcmpl-${Date.now()}`,\r\n object: \"chat.completion\",\r\n created: Math.floor(Date.now() / 1000),\r\n model: response.metadata?.model,\r\n choices: [\r\n {\r\n index: 0,\r\n message: {\r\n role: \"assistant\",\r\n content,\r\n },\r\n finish_reason: \"stop\",\r\n },\r\n ],\r\n usage: response.metadata?.usage || {\r\n prompt_tokens: 0,\r\n completion_tokens: 0,\r\n total_tokens: 0,\r\n },\r\n };\r\n }\r\n\r\n /**\r\n * Parse SSE stream into async iterable of OpenAI-like chunks\r\n */\r\n private async *parseSSEStream(\r\n response: Response,\r\n model: string\r\n ): AsyncIterableIterator<any> {\r\n const reader = response.body!.getReader();\r\n const decoder = new TextDecoder();\r\n let buffer = \"\";\r\n\r\n try {\r\n while (true) {\r\n const { done, value } = await reader.read();\r\n if (done) break;\r\n\r\n buffer += decoder.decode(value, { stream: true });\r\n const lines = buffer.split(\"\\n\");\r\n buffer = lines.pop() || \"\";\r\n\r\n for (const line of lines) {\r\n if (line.startsWith(\"data: \")) {\r\n const dataStr = line.slice(6).trim();\r\n if (dataStr) {\r\n try {\r\n const data = JSON.parse(dataStr);\r\n\r\n // Transform to OpenAI-like streaming format\r\n if (data.chunk || data.content) {\r\n yield {\r\n id: `chatcmpl-${Date.now()}`,\r\n object: \"chat.completion.chunk\",\r\n created: Math.floor(Date.now() / 1000),\r\n model,\r\n choices: [\r\n {\r\n index: 0,\r\n delta: {\r\n content: data.chunk || data.content,\r\n },\r\n finish_reason: data.done ? \"stop\" : null,\r\n },\r\n ],\r\n };\r\n }\r\n\r\n // If we received the done signal, we can stop\r\n if (data.done) {\r\n reader.releaseLock();\r\n return;\r\n }\r\n } catch (e) {\r\n // Skip invalid JSON\r\n console.warn(\"Failed to parse SSE data:\", dataStr);\r\n }\r\n }\r\n }\r\n }\r\n }\r\n } finally {\r\n reader.releaseLock();\r\n }\r\n }\r\n}\r\n\r\nclass Images {\r\n constructor(private http: HttpClient) {}\r\n\r\n /**\r\n * Generate images - OpenAI-like response format\r\n *\r\n * @example\r\n * ```typescript\r\n * // Text-to-image\r\n * const response = await client.ai.images.generate({\r\n * model: 'dall-e-3',\r\n * prompt: 'A sunset over mountains',\r\n * });\r\n * console.log(response.images[0].url);\r\n *\r\n * // Image-to-image (with input images)\r\n * const response = await client.ai.images.generate({\r\n * model: 'stable-diffusion-xl',\r\n * prompt: 'Transform this into a watercolor painting',\r\n * images: [\r\n * { url: 'https://example.com/input.jpg' },\r\n * // or base64-encoded Data URI:\r\n * { url: 'data:image/jpeg;base64,/9j/4AAQ...' }\r\n * ]\r\n * });\r\n * ```\r\n */\r\n async generate(params: ImageGenerationRequest): Promise<any> {\r\n const response: ImageGenerationResponse = await this.http.post(\r\n \"/api/ai/image/generation\",\r\n params\r\n );\r\n \r\n // Build data array based on response content\r\n let data: Array<{ b64_json?: string; content?: string }> = [];\r\n \r\n if (response.images && response.images.length > 0) {\r\n // Has images - extract base64 and include text\r\n data = response.images.map(img => ({\r\n b64_json: img.imageUrl.replace(/^data:image\\/\\w+;base64,/, ''),\r\n content: response.text\r\n }));\r\n } else if (response.text) {\r\n // Text-only response\r\n data = [{ content: response.text }];\r\n }\r\n \r\n // Return OpenAI-compatible format\r\n return {\r\n created: Math.floor(Date.now() / 1000),\r\n data,\r\n ...(response.metadata?.usage && {\r\n usage: {\r\n total_tokens: response.metadata.usage.totalTokens || 0,\r\n input_tokens: response.metadata.usage.promptTokens || 0,\r\n output_tokens: response.metadata.usage.completionTokens || 0,\r\n }\r\n })\r\n };\r\n }\r\n}\r\n","import { HttpClient } from '../lib/http-client';\r\n\r\nexport interface FunctionInvokeOptions {\r\n /**\r\n * The body of the request\r\n */\r\n body?: any;\r\n \r\n /**\r\n * Custom headers to send with the request\r\n */\r\n headers?: Record<string, string>;\r\n \r\n /**\r\n * HTTP method (default: POST)\r\n */\r\n method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';\r\n}\r\n\r\n/**\r\n * Edge Functions client for invoking serverless functions\r\n * \r\n * @example\r\n * ```typescript\r\n * // Invoke a function with JSON body\r\n * const { data, error } = await client.functions.invoke('hello-world', {\r\n * body: { name: 'World' }\r\n * });\r\n * \r\n * // GET request\r\n * const { data, error } = await client.functions.invoke('get-data', {\r\n * method: 'GET'\r\n * });\r\n * ```\r\n */\r\nexport class Functions {\r\n private http: HttpClient;\r\n\r\n constructor(http: HttpClient) {\r\n this.http = http;\r\n }\r\n\r\n /**\r\n * Invokes an Edge Function\r\n * @param slug The function slug to invoke\r\n * @param options Request options\r\n */\r\n async invoke<T = any>(\r\n slug: string,\r\n options: FunctionInvokeOptions = {}\r\n ): Promise<{ data: T | null; error: Error | null }> {\r\n try {\r\n const { method = 'POST', body, headers = {} } = options;\r\n \r\n // Simple path: /functions/{slug}\r\n const path = `/functions/${slug}`;\r\n \r\n // Use the HTTP client's request method\r\n const data = await this.http.request<T>(\r\n method,\r\n path,\r\n { body, headers }\r\n );\r\n \r\n return { data, error: null };\r\n } catch (error: any) {\r\n // The HTTP client throws InsForgeError with all properties from the response\r\n // including error, message, details, statusCode, etc.\r\n // We need to preserve all of that information\r\n return { \r\n data: null, \r\n error: error // Pass through the full error object with all properties\r\n };\r\n }\r\n }\r\n}","import { InsForgeConfig } from './types';\r\nimport { HttpClient } from './lib/http-client';\r\nimport { TokenManager } from './lib/token-manager';\r\nimport { SecureSessionStorage, AUTH_FLAG_COOKIE } from './lib/session-storage';\r\nimport { Auth } from './modules/auth';\r\nimport { Database } from './modules/database-postgrest';\r\nimport { Storage } from './modules/storage';\r\nimport { AI } from './modules/ai';\r\nimport { Functions } from './modules/functions';\r\n\r\n/**\r\n * Check if the isAuthenticated cookie flag exists (SDK-managed on frontend domain)\r\n * This indicates a previous secure session was established and we should use SecureSessionStorage\r\n */\r\nfunction hasAuthenticatedCookie(): boolean {\r\n if (typeof document === 'undefined') return false;\r\n return document.cookie.split(';').some(c =>\r\n c.trim().startsWith(`${AUTH_FLAG_COOKIE}=`)\r\n );\r\n}\r\n\r\n/**\r\n * Main InsForge SDK Client\r\n * \r\n * @example\r\n * ```typescript\r\n * import { InsForgeClient } from '@insforge/sdk';\r\n * \r\n * const client = new InsForgeClient({\r\n * baseUrl: 'http://localhost:7130'\r\n * });\r\n * \r\n * // Authentication\r\n * const { data, error } = await client.auth.signUp({\r\n * email: 'user@example.com',\r\n * password: 'password123',\r\n * name: 'John Doe'\r\n * });\r\n * \r\n * // Database operations\r\n * const { data, error } = await client.database\r\n * .from('posts')\r\n * .select('*')\r\n * .eq('user_id', session.user.id)\r\n * .order('created_at', { ascending: false })\r\n * .limit(10);\r\n * \r\n * // Insert data\r\n * const { data: newPost } = await client.database\r\n * .from('posts')\r\n * .insert({ title: 'Hello', content: 'World' })\r\n * .single();\r\n * \r\n * // Invoke edge functions\r\n * const { data, error } = await client.functions.invoke('my-function', {\r\n * body: { message: 'Hello from SDK' }\r\n * });\r\n * ```\r\n */\r\nexport class InsForgeClient {\r\n private http: HttpClient;\r\n private tokenManager: TokenManager;\r\n public readonly auth: Auth;\r\n public readonly database: Database;\r\n public readonly storage: Storage;\r\n public readonly ai: AI;\r\n public readonly functions: Functions;\r\n\r\n constructor(config: InsForgeConfig = {}) {\r\n this.http = new HttpClient(config);\r\n this.tokenManager = new TokenManager(config.storage);\r\n\r\n // Detect storage strategy based on SDK-managed cookie flag (on frontend domain)\r\n // If isAuthenticated cookie exists, a previous secure session was established\r\n if (hasAuthenticatedCookie()) {\r\n this.tokenManager.setStrategy(new SecureSessionStorage());\r\n }\r\n // Otherwise, keep default LocalSessionStorage (will switch if backend returns sessionMode: 'secure')\r\n\r\n // Check for edge function token\r\n if (config.edgeFunctionToken) {\r\n this.http.setAuthToken(config.edgeFunctionToken);\r\n // Save to token manager so getCurrentUser() works\r\n this.tokenManager.saveSession({\r\n accessToken: config.edgeFunctionToken,\r\n user: {} as any, // Will be populated by getCurrentUser()\r\n });\r\n }\r\n\r\n // Set up refresh callback for auto-refresh on 401\r\n // On 401, if refresh fails and we're using SecureSessionStorage, \r\n // fall back to LocalSessionStorage\r\n this.http.setRefreshCallback(async () => {\r\n try {\r\n return await this.auth.refreshToken();\r\n } catch {\r\n // If refresh failed and we're in secure mode, cookie might be invalid\r\n // Fall back to localStorage mode\r\n if (this.tokenManager.getStrategyId() === 'secure') {\r\n this.auth._switchToLocalStorage();\r\n }\r\n return null;\r\n }\r\n });\r\n\r\n // Check for existing session\r\n // In secure mode: try to refresh to get access token\r\n // In local mode: check localStorage\r\n const existingSession = this.tokenManager.getSession();\r\n if (existingSession?.accessToken) {\r\n this.http.setAuthToken(existingSession.accessToken);\r\n } else if (this.tokenManager.getStrategyId() === 'secure') {\r\n // Secure mode but no session in memory - need to refresh\r\n // This happens on page reload with cookie auth\r\n // Will be handled by first API call triggering 401 -> refresh\r\n }\r\n\r\n this.auth = new Auth(this.http, this.tokenManager);\r\n this.database = new Database(this.http, this.tokenManager);\r\n this.storage = new Storage(this.http);\r\n this.ai = new AI(this.http);\r\n this.functions = new Functions(this.http);\r\n }\r\n\r\n /**\r\n * Get the underlying HTTP client for custom requests\r\n * \r\n * @example\r\n * ```typescript\r\n * const httpClient = client.getHttpClient();\r\n * const customData = await httpClient.get('/api/custom-endpoint');\r\n * ```\r\n */\r\n getHttpClient(): HttpClient {\r\n return this.http;\r\n }\r\n\r\n /**\r\n * Get the current storage strategy identifier\r\n */\r\n getStorageStrategy(): string {\r\n return this.tokenManager.getStrategyId();\r\n }\r\n\r\n /**\r\n * Future modules will be added here:\r\n * - database: Database operations\r\n * - storage: File storage operations\r\n * - functions: Serverless functions\r\n * - tables: Table management\r\n * - metadata: Backend metadata\r\n */\r\n}\r\n"],"mappings":"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","names":["data","error","response"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/types.ts","../src/lib/http-client.ts","../src/lib/session-storage.ts","../src/lib/token-manager.ts","../src/modules/database-postgrest.ts","../src/modules/auth.ts","../src/modules/storage.ts","../src/modules/ai.ts","../src/modules/functions.ts","../src/client.ts"],"sourcesContent":["/**\r\n * @insforge/sdk - TypeScript SDK for InsForge Backend-as-a-Service\r\n * \r\n * @packageDocumentation\r\n */\r\n\r\n// Main client\r\nexport { InsForgeClient } from './client';\r\n\r\n// Types\r\nexport type {\r\n InsForgeConfig,\r\n InsForgeConfig as ClientOptions, // Alias for compatibility\r\n TokenStorage,\r\n AuthSession,\r\n ApiError,\r\n} from './types';\r\n\r\nexport { InsForgeError } from './types';\r\n\r\n// Re-export shared schemas that SDK users will need\r\nexport type {\r\n UserSchema,\r\n CreateUserRequest,\r\n CreateSessionRequest,\r\n AuthErrorResponse,\r\n} from '@insforge/shared-schemas';\r\n\r\n// Re-export auth module for advanced usage\r\nexport { Auth } from './modules/auth';\r\n\r\nexport type { ProfileData, UpdateProfileData } from './modules/auth';\r\n\r\n// Re-export database module (using postgrest-js)\r\nexport { Database } from './modules/database-postgrest';\r\n// Note: QueryBuilder is no longer exported as we use postgrest-js QueryBuilder internally\r\n\r\n// Re-export storage module and types\r\nexport { Storage, StorageBucket } from './modules/storage';\r\nexport type { StorageResponse } from './modules/storage';\r\n\r\n// Re-export AI module\r\nexport { AI } from './modules/ai';\r\n\r\n// Re-export Functions module\r\nexport { Functions } from './modules/functions';\r\nexport type { FunctionInvokeOptions } from './modules/functions';\r\n\r\n// Re-export utilities for advanced usage\r\nexport { HttpClient } from './lib/http-client';\r\nexport { TokenManager } from './lib/token-manager';\r\n\r\n// Re-export session storage strategies for advanced usage\r\nexport {\r\n SecureSessionStorage,\r\n LocalSessionStorage,\r\n} from './lib/session-storage';\r\nexport type { SessionStorageStrategy } from './lib/session-storage';\r\n\r\n// Factory function for creating clients (Supabase-style)\r\nimport { InsForgeClient } from './client';\r\nimport { InsForgeConfig } from './types';\r\n\r\nexport function createClient(config: InsForgeConfig): InsForgeClient {\r\n return new InsForgeClient(config);\r\n}\r\n\r\n// Default export for convenience\r\nexport default InsForgeClient;\r\n","/**\r\n * InsForge SDK Types - only SDK-specific types here\r\n * Use @insforge/shared-schemas directly for API types\r\n */\r\n\r\nimport type { UserSchema } from '@insforge/shared-schemas';\r\n\r\nexport interface InsForgeConfig {\r\n /**\r\n * The base URL of the InsForge backend API\r\n * @default \"http://localhost:7130\"\r\n */\r\n baseUrl?: string;\r\n\r\n /**\r\n * Anonymous API key (optional)\r\n * Used for public/unauthenticated requests when no user token is set\r\n */\r\n anonKey?: string;\r\n\r\n /**\r\n * Edge Function Token (optional)\r\n * Use this when running in edge functions/serverless with a user's JWT token\r\n * This token will be used for all authenticated requests\r\n */\r\n edgeFunctionToken?: string;\r\n\r\n /**\r\n * Custom fetch implementation (useful for Node.js environments)\r\n */\r\n fetch?: typeof fetch;\r\n\r\n /**\r\n * Storage adapter for persisting tokens\r\n */\r\n storage?: TokenStorage;\r\n\r\n /**\r\n * Whether to automatically refresh tokens before they expire\r\n * @default true\r\n */\r\n autoRefreshToken?: boolean;\r\n\r\n /**\r\n * Whether to persist session in storage\r\n * @default true\r\n */\r\n persistSession?: boolean;\r\n\r\n /**\r\n * Custom headers to include with every request\r\n */\r\n headers?: Record<string, string>;\r\n}\r\n\r\nexport interface TokenStorage {\r\n getItem(key: string): string | null | Promise<string | null>;\r\n setItem(key: string, value: string): void | Promise<void>;\r\n removeItem(key: string): void | Promise<void>;\r\n}\r\n\r\nexport interface AuthSession {\r\n user: UserSchema;\r\n accessToken: string;\r\n expiresAt?: Date;\r\n}\r\n\r\nexport interface ApiError {\r\n error: string;\r\n message: string;\r\n statusCode: number;\r\n nextActions?: string;\r\n}\r\n\r\nexport class InsForgeError extends Error {\r\n public statusCode: number;\r\n public error: string;\r\n public nextActions?: string;\r\n\r\n constructor(message: string, statusCode: number, error: string, nextActions?: string) {\r\n super(message);\r\n this.name = 'InsForgeError';\r\n this.statusCode = statusCode;\r\n this.error = error;\r\n this.nextActions = nextActions;\r\n }\r\n\r\n static fromApiError(apiError: ApiError): InsForgeError {\r\n return new InsForgeError(\r\n apiError.message,\r\n apiError.statusCode,\r\n apiError.error,\r\n apiError.nextActions\r\n );\r\n }\r\n}","import { InsForgeConfig, ApiError, InsForgeError } from '../types';\r\n\r\nexport interface RequestOptions extends RequestInit {\r\n params?: Record<string, string>;\r\n}\r\n\r\n/**\r\n * Callback type for token refresh\r\n * Returns new access token or null if refresh failed\r\n */\r\nexport type RefreshCallback = () => Promise<string | null>;\r\n\r\nexport class HttpClient {\r\n public readonly baseUrl: string;\r\n public readonly fetch: typeof fetch;\r\n private defaultHeaders: Record<string, string>;\r\n private anonKey: string | undefined;\r\n private userToken: string | null = null;\r\n \r\n // Auto-refresh support\r\n private refreshCallback?: RefreshCallback;\r\n private isRefreshing = false;\r\n private refreshQueue: Array<{\r\n resolve: (token: string) => void;\r\n reject: (error: Error) => void;\r\n }> = [];\r\n\r\n constructor(config: InsForgeConfig) {\r\n this.baseUrl = config.baseUrl || 'http://localhost:7130';\r\n // Properly bind fetch to maintain its context\r\n this.fetch = config.fetch || (globalThis.fetch ? globalThis.fetch.bind(globalThis) : undefined as any);\r\n this.anonKey = config.anonKey;\r\n this.defaultHeaders = {\r\n ...config.headers,\r\n };\r\n\r\n if (!this.fetch) {\r\n throw new Error(\r\n 'Fetch is not available. Please provide a fetch implementation in the config.'\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Set the refresh callback for automatic token refresh on 401\r\n */\r\n setRefreshCallback(callback: RefreshCallback): void {\r\n this.refreshCallback = callback;\r\n }\r\n\r\n private buildUrl(path: string, params?: Record<string, string>): string {\r\n const url = new URL(path, this.baseUrl);\r\n if (params) {\r\n Object.entries(params).forEach(([key, value]) => {\r\n // For select parameter, preserve the exact formatting by normalizing whitespace\r\n // This ensures PostgREST relationship queries work correctly\r\n if (key === 'select') {\r\n // Normalize multiline select strings for PostgREST:\r\n // 1. Replace all whitespace (including newlines) with single space\r\n // 2. Remove spaces inside parentheses for proper PostgREST syntax\r\n // 3. Keep spaces after commas at the top level for readability\r\n let normalizedValue = value.replace(/\\s+/g, ' ').trim();\r\n \r\n // Fix spaces around parentheses and inside them\r\n normalizedValue = normalizedValue\r\n .replace(/\\s*\\(\\s*/g, '(') // Remove spaces around opening parens\r\n .replace(/\\s*\\)\\s*/g, ')') // Remove spaces around closing parens\r\n .replace(/\\(\\s+/g, '(') // Remove spaces after opening parens\r\n .replace(/\\s+\\)/g, ')') // Remove spaces before closing parens\r\n .replace(/,\\s+(?=[^()]*\\))/g, ','); // Remove spaces after commas inside parens\r\n \r\n url.searchParams.append(key, normalizedValue);\r\n } else {\r\n url.searchParams.append(key, value);\r\n }\r\n });\r\n }\r\n return url.toString();\r\n }\r\n\r\n async request<T>(\r\n method: string,\r\n path: string,\r\n options: RequestOptions = {}\r\n ): Promise<T> {\r\n return this.performRequest<T>(method, path, options, false);\r\n }\r\n\r\n private async performRequest<T>(\r\n method: string,\r\n path: string,\r\n options: RequestOptions = {},\r\n isRetry = false\r\n ): Promise<T> {\r\n const { params, headers = {}, body, ...fetchOptions } = options;\r\n \r\n const url = this.buildUrl(path, params);\r\n \r\n const requestHeaders: Record<string, string> = {\r\n ...this.defaultHeaders,\r\n };\r\n \r\n // Set Authorization header: prefer user token, fallback to anon key\r\n const authToken = this.userToken || this.anonKey;\r\n if (authToken) {\r\n requestHeaders['Authorization'] = `Bearer ${authToken}`;\r\n }\r\n \r\n // Handle body serialization\r\n let processedBody: any;\r\n if (body !== undefined) {\r\n // Check if body is FormData (for file uploads)\r\n if (typeof FormData !== 'undefined' && body instanceof FormData) {\r\n // Don't set Content-Type for FormData, let browser set it with boundary\r\n processedBody = body;\r\n } else {\r\n // JSON body\r\n if (method !== 'GET') {\r\n requestHeaders['Content-Type'] = 'application/json;charset=UTF-8';\r\n }\r\n processedBody = JSON.stringify(body);\r\n }\r\n }\r\n \r\n Object.assign(requestHeaders, headers);\r\n \r\n const response = await this.fetch(url, {\r\n method,\r\n headers: requestHeaders,\r\n body: processedBody,\r\n ...fetchOptions,\r\n credentials: 'include',\r\n });\r\n\r\n // Handle 401 with automatic refresh (only if we have a refresh callback and this isn't already a retry)\r\n const isRefreshEndpoint = path.includes('/api/auth/refresh') || path.includes('/api/auth/logout');\r\n if (response.status === 401 && !isRetry && !isRefreshEndpoint && this.refreshCallback) {\r\n const newToken = await this.handleTokenRefresh();\r\n if (newToken) {\r\n this.setAuthToken(newToken);\r\n return this.performRequest<T>(method, path, options, true);\r\n }\r\n }\r\n\r\n // Handle 204 No Content\r\n if (response.status === 204) {\r\n return undefined as T;\r\n }\r\n\r\n // Try to parse JSON response\r\n let data: any;\r\n const contentType = response.headers.get('content-type');\r\n // Check for any JSON content type (including PostgREST's vnd.pgrst.object+json)\r\n if (contentType?.includes('json')) {\r\n data = await response.json();\r\n } else {\r\n // For non-JSON responses, return text\r\n data = await response.text();\r\n }\r\n\r\n // Handle errors\r\n if (!response.ok) {\r\n if (data && typeof data === 'object' && 'error' in data) {\r\n // Add the HTTP status code if not already in the data\r\n if (!data.statusCode && !data.status) {\r\n data.statusCode = response.status;\r\n }\r\n const error = InsForgeError.fromApiError(data as ApiError);\r\n // Preserve all additional fields from the error response\r\n Object.keys(data).forEach(key => {\r\n if (key !== 'error' && key !== 'message' && key !== 'statusCode') {\r\n (error as any)[key] = data[key];\r\n }\r\n });\r\n throw error;\r\n }\r\n throw new InsForgeError(\r\n `Request failed: ${response.statusText}`,\r\n response.status,\r\n 'REQUEST_FAILED'\r\n );\r\n }\r\n\r\n return data as T;\r\n }\r\n\r\n /**\r\n * Handle token refresh with queue to prevent duplicate refreshes\r\n * Multiple concurrent 401s will wait for a single refresh to complete\r\n */\r\n private async handleTokenRefresh(): Promise<string | null> {\r\n // If already refreshing, queue this request\r\n if (this.isRefreshing) {\r\n return new Promise((resolve, reject) => {\r\n this.refreshQueue.push({ resolve, reject });\r\n });\r\n }\r\n\r\n this.isRefreshing = true;\r\n\r\n try {\r\n const newToken = await this.refreshCallback?.();\r\n \r\n // Resolve all queued requests with the new token (or null if refresh failed)\r\n this.refreshQueue.forEach(({ resolve, reject }) => {\r\n if (newToken) {\r\n resolve(newToken);\r\n } else {\r\n reject(new Error('Token refresh failed'));\r\n }\r\n });\r\n this.refreshQueue = [];\r\n \r\n return newToken || null;\r\n } catch (error) {\r\n // Reject all queued requests\r\n this.refreshQueue.forEach(({ reject }) => {\r\n reject(error instanceof Error ? error : new Error('Token refresh failed'));\r\n });\r\n this.refreshQueue = [];\r\n \r\n return null;\r\n } finally {\r\n this.isRefreshing = false;\r\n }\r\n }\r\n\r\n get<T>(path: string, options?: RequestOptions): Promise<T> {\r\n return this.request<T>('GET', path, options);\r\n }\r\n\r\n post<T>(path: string, body?: any, options?: RequestOptions): Promise<T> {\r\n return this.request<T>('POST', path, { ...options, body });\r\n }\r\n\r\n put<T>(path: string, body?: any, options?: RequestOptions): Promise<T> {\r\n return this.request<T>('PUT', path, { ...options, body });\r\n }\r\n\r\n patch<T>(path: string, body?: any, options?: RequestOptions): Promise<T> {\r\n return this.request<T>('PATCH', path, { ...options, body });\r\n }\r\n\r\n delete<T>(path: string, options?: RequestOptions): Promise<T> {\r\n return this.request<T>('DELETE', path, options);\r\n }\r\n\r\n setAuthToken(token: string | null) {\r\n this.userToken = token;\r\n }\r\n\r\n getHeaders(): Record<string, string> {\r\n const headers = { ...this.defaultHeaders };\r\n \r\n // Include Authorization header if token is available (same logic as request method)\r\n const authToken = this.userToken || this.anonKey;\r\n if (authToken) {\r\n headers['Authorization'] = `Bearer ${authToken}`;\r\n }\r\n \r\n return headers;\r\n }\r\n}\r\n","/**\n * Session Storage Strategies for InsForge SDK\n * \n * Implements the Strategy Pattern for token storage:\n * - SecureSessionStorage: In-memory tokens + httpOnly cookie refresh (XSS-resistant)\n * - LocalSessionStorage: localStorage-based storage (legacy/fallback)\n */\n\nimport type { UserSchema } from '@insforge/shared-schemas';\nimport type { AuthSession, TokenStorage } from '../types';\n\n// localStorage keys for persistent storage\nexport const TOKEN_KEY = 'insforge-auth-token';\nexport const USER_KEY = 'insforge-auth-user';\n\n// Cookie name for optimistic refresh flag\nexport const AUTH_FLAG_COOKIE = 'isAuthenticated';\n\n/**\n * Strategy interface for session storage\n * All storage implementations must conform to this interface\n */\nexport interface SessionStorageStrategy {\n /** Save complete session (token + user) */\n saveSession(session: AuthSession): void;\n \n /** Get current session */\n getSession(): AuthSession | null;\n \n /** Get access token only */\n getAccessToken(): string | null;\n \n /** Update access token (e.g., after refresh) */\n setAccessToken(token: string): void;\n \n /** Get user data */\n getUser(): UserSchema | null;\n \n /** Update user data */\n setUser(user: UserSchema): void;\n \n /** Clear all session data */\n clearSession(): void;\n \n /** Check if token refresh should be attempted (e.g., on page reload) */\n shouldAttemptRefresh(): boolean;\n \n /** Get strategy identifier for debugging */\n readonly strategyId: string;\n}\n\n/**\n * Secure Session Storage Strategy\n * \n * Stores access token in memory only (cleared on page refresh).\n * Refresh token is stored in httpOnly cookie by the backend (on backend domain).\n * The `isAuthenticated` cookie is set by the SDK on the frontend domain to signal\n * that a secure session exists and token refresh should be attempted on page reload.\n * \n * Security benefits:\n * - Access token not accessible to XSS attacks (in memory only)\n * - Refresh token completely inaccessible to JavaScript (httpOnly)\n */\nexport class SecureSessionStorage implements SessionStorageStrategy {\n readonly strategyId = 'secure';\n \n private accessToken: string | null = null;\n private user: UserSchema | null = null;\n\n saveSession(session: AuthSession): void {\n this.accessToken = session.accessToken;\n this.user = session.user;\n }\n\n getSession(): AuthSession | null {\n if (!this.accessToken || !this.user) return null;\n return {\n accessToken: this.accessToken,\n user: this.user,\n };\n }\n\n getAccessToken(): string | null {\n return this.accessToken;\n }\n\n setAccessToken(token: string): void {\n this.accessToken = token;\n }\n\n getUser(): UserSchema | null {\n return this.user;\n }\n\n setUser(user: UserSchema): void {\n this.user = user;\n }\n\n clearSession(): void {\n this.accessToken = null;\n this.user = null;\n }\n\n shouldAttemptRefresh(): boolean {\n // Attempt refresh if:\n // 1. No token in memory (page was refreshed)\n // 2. Auth flag cookie exists (SDK set it on frontend domain after successful auth)\n if (this.accessToken) return false;\n return this.hasAuthFlag();\n }\n\n // --- Private: Auth Flag Cookie Detection (SDK-managed on frontend domain) ---\n\n private hasAuthFlag(): boolean {\n if (typeof document === 'undefined') return false;\n return document.cookie.split(';').some(c => \n c.trim().startsWith(`${AUTH_FLAG_COOKIE}=`)\n );\n }\n}\n\n/**\n * Local Session Storage Strategy\n * \n * Stores tokens in localStorage for persistence across page reloads.\n * Used for legacy backends or environments where httpOnly cookies aren't available.\n * \n * Note: This approach exposes tokens to XSS attacks. Use SecureSessionStorage\n * when possible.\n */\nexport class LocalSessionStorage implements SessionStorageStrategy {\n readonly strategyId = 'local';\n \n private storage: TokenStorage;\n\n constructor(storage?: TokenStorage) {\n if (storage) {\n this.storage = storage;\n } else if (typeof window !== 'undefined' && window.localStorage) {\n this.storage = window.localStorage;\n } else {\n // Fallback: in-memory storage for Node.js environments\n const store = new Map<string, string>();\n this.storage = {\n getItem: (key: string) => store.get(key) || null,\n setItem: (key: string, value: string) => { store.set(key, value); },\n removeItem: (key: string) => { store.delete(key); },\n };\n }\n }\n\n saveSession(session: AuthSession): void {\n this.storage.setItem(TOKEN_KEY, session.accessToken);\n this.storage.setItem(USER_KEY, JSON.stringify(session.user));\n }\n\n getSession(): AuthSession | null {\n const token = this.storage.getItem(TOKEN_KEY);\n const userStr = this.storage.getItem(USER_KEY);\n\n if (!token || !userStr) return null;\n\n try {\n const user = JSON.parse(userStr as string);\n return { accessToken: token as string, user };\n } catch {\n this.clearSession();\n return null;\n }\n }\n\n getAccessToken(): string | null {\n const token = this.storage.getItem(TOKEN_KEY);\n return typeof token === 'string' ? token : null;\n }\n\n setAccessToken(token: string): void {\n this.storage.setItem(TOKEN_KEY, token);\n }\n\n getUser(): UserSchema | null {\n const userStr = this.storage.getItem(USER_KEY);\n if (!userStr) return null;\n try {\n return JSON.parse(userStr as string);\n } catch {\n return null;\n }\n }\n\n setUser(user: UserSchema): void {\n this.storage.setItem(USER_KEY, JSON.stringify(user));\n }\n\n clearSession(): void {\n this.storage.removeItem(TOKEN_KEY);\n this.storage.removeItem(USER_KEY);\n }\n\n shouldAttemptRefresh(): boolean {\n // In persistent mode, we always have the token in storage\n // No need to refresh on page load\n return false;\n }\n}\n","/**\r\n * Token Manager for InsForge SDK\r\n * \r\n * A thin wrapper that delegates to the underlying SessionStorageStrategy.\r\n * This class maintains backward compatibility while using the Strategy Pattern internally.\r\n */\r\n\r\nimport type { UserSchema } from '@insforge/shared-schemas';\r\nimport type { AuthSession, TokenStorage } from '../types';\r\nimport {\r\n SessionStorageStrategy,\r\n LocalSessionStorage,\r\n} from './session-storage';\r\n\r\n/**\r\n * TokenManager - Manages session storage using the Strategy Pattern\r\n * \r\n * The actual storage implementation is delegated to a SessionStorageStrategy.\r\n * By default, uses LocalSessionStorage until a strategy is explicitly set\r\n * via setStrategy() during client initialization.\r\n */\r\nexport class TokenManager {\r\n private strategy: SessionStorageStrategy;\r\n\r\n /**\r\n * Create a new TokenManager\r\n * @param storage - Optional custom storage adapter (used for initial LocalSessionStorage)\r\n */\r\n constructor(storage?: TokenStorage) {\r\n // Default to persistent storage until capability discovery completes\r\n this.strategy = new LocalSessionStorage(storage);\r\n }\r\n\r\n /**\r\n * Set the storage strategy\r\n * Called after capability discovery to switch to the appropriate strategy\r\n */\r\n setStrategy(strategy: SessionStorageStrategy): void {\r\n // Migrate existing session data if switching strategies\r\n const existingSession = this.strategy.getSession();\r\n const previousId = this.strategy.strategyId;\r\n \r\n this.strategy = strategy;\r\n \r\n // If we had a session and are switching to a different strategy, migrate it\r\n if (existingSession && previousId !== strategy.strategyId) {\r\n strategy.saveSession(existingSession);\r\n }\r\n }\r\n\r\n /**\r\n * Get the current strategy identifier\r\n */\r\n getStrategyId(): string {\r\n return this.strategy.strategyId;\r\n }\r\n\r\n // --- Delegated Methods ---\r\n\r\n /**\r\n * Save session data\r\n */\r\n saveSession(session: AuthSession): void {\r\n this.strategy.saveSession(session);\r\n }\r\n\r\n /**\r\n * Get current session\r\n */\r\n getSession(): AuthSession | null {\r\n return this.strategy.getSession();\r\n }\r\n\r\n /**\r\n * Get access token\r\n */\r\n getAccessToken(): string | null {\r\n return this.strategy.getAccessToken();\r\n }\r\n\r\n /**\r\n * Update access token (e.g., after refresh)\r\n */\r\n setAccessToken(token: string): void {\r\n this.strategy.setAccessToken(token);\r\n }\r\n\r\n /**\r\n * Get user data\r\n */\r\n getUser(): UserSchema | null {\r\n return this.strategy.getUser();\r\n }\r\n\r\n /**\r\n * Update user data\r\n */\r\n setUser(user: UserSchema): void {\r\n this.strategy.setUser(user);\r\n }\r\n\r\n /**\r\n * Clear all session data\r\n */\r\n clearSession(): void {\r\n this.strategy.clearSession();\r\n }\r\n\r\n /**\r\n * Check if token refresh should be attempted\r\n * (e.g., on page reload in secure mode)\r\n */\r\n shouldAttemptRefresh(): boolean {\r\n return this.strategy.shouldAttemptRefresh();\r\n }\r\n}\r\n","/**\r\n * Database module using @supabase/postgrest-js\r\n * Complete replacement for custom QueryBuilder with full PostgREST features\r\n */\r\n\r\nimport { PostgrestClient } from '@supabase/postgrest-js';\r\nimport { HttpClient } from '../lib/http-client';\r\nimport { TokenManager } from '../lib/token-manager';\r\n\r\n\r\n/**\r\n * Custom fetch that transforms URLs and adds auth\r\n */\r\nfunction createInsForgePostgrestFetch(\r\n httpClient: HttpClient,\r\n tokenManager: TokenManager\r\n): typeof fetch {\r\n return async (input: RequestInfo | URL, init?: RequestInit): Promise<Response> => {\r\n const url = typeof input === 'string' ? input : input.toString();\r\n const urlObj = new URL(url);\r\n \r\n // Extract table name from pathname\r\n // postgrest-js sends: http://dummy/tablename?params\r\n // We need: http://localhost:7130/api/database/records/tablename?params\r\n const tableName = urlObj.pathname.slice(1); // Remove leading /\r\n \r\n // Build InsForge URL\r\n const insforgeUrl = `${httpClient.baseUrl}/api/database/records/${tableName}${urlObj.search}`;\r\n \r\n // Get auth token from TokenManager or HttpClient\r\n const token = tokenManager.getAccessToken();\r\n const httpHeaders = httpClient.getHeaders();\r\n const authToken = token || httpHeaders['Authorization']?.replace('Bearer ', '');\r\n \r\n // Prepare headers\r\n const headers = new Headers(init?.headers);\r\n if (authToken && !headers.has('Authorization')) {\r\n headers.set('Authorization', `Bearer ${authToken}`);\r\n }\r\n \r\n // Make the actual request using native fetch\r\n const response = await fetch(insforgeUrl, {\r\n ...init,\r\n headers\r\n });\r\n \r\n return response;\r\n };\r\n}\r\n\r\n/**\r\n * Database client using postgrest-js\r\n * Drop-in replacement with FULL PostgREST capabilities\r\n */\r\nexport class Database {\r\n private postgrest: PostgrestClient<any, any, any>;\r\n \r\n constructor(httpClient: HttpClient, tokenManager: TokenManager) {\r\n // Create postgrest client with custom fetch\r\n this.postgrest = new PostgrestClient<any, any, any>('http://dummy', {\r\n fetch: createInsForgePostgrestFetch(httpClient, tokenManager),\r\n headers: {}\r\n });\r\n }\r\n \r\n /**\r\n * Create a query builder for a table\r\n * \r\n * @example\r\n * // Basic query\r\n * const { data, error } = await client.database\r\n * .from('posts')\r\n * .select('*')\r\n * .eq('user_id', userId);\r\n * \r\n * // With count (Supabase style!)\r\n * const { data, error, count } = await client.database\r\n * .from('posts')\r\n * .select('*', { count: 'exact' })\r\n * .range(0, 9);\r\n * \r\n * // Just get count, no data\r\n * const { count } = await client.database\r\n * .from('posts')\r\n * .select('*', { count: 'exact', head: true });\r\n * \r\n * // Complex queries with OR\r\n * const { data } = await client.database\r\n * .from('posts')\r\n * .select('*, users!inner(*)')\r\n * .or('status.eq.active,status.eq.pending');\r\n * \r\n * // All features work:\r\n * - Nested selects\r\n * - Foreign key expansion \r\n * - OR/AND/NOT conditions\r\n * - Count with head\r\n * - Range pagination\r\n * - Upserts\r\n */\r\n from(table: string) {\r\n // Return postgrest query builder with all features\r\n return this.postgrest.from(table);\r\n }\r\n}","/**\n * Auth module for InsForge SDK\n * Uses shared schemas for type safety\n */\n\nimport { HttpClient } from '../lib/http-client';\nimport { TokenManager } from '../lib/token-manager';\nimport { SecureSessionStorage, LocalSessionStorage, AUTH_FLAG_COOKIE, TOKEN_KEY, USER_KEY } from '../lib/session-storage';\nimport { AuthSession, InsForgeError } from '../types';\nimport { Database } from './database-postgrest';\n\nimport type {\n CreateUserRequest,\n CreateUserResponse,\n CreateSessionRequest,\n CreateSessionResponse,\n GetCurrentSessionResponse,\n GetOauthUrlResponse,\n GetPublicAuthConfigResponse,\n OAuthProvidersSchema,\n UserIdSchema,\n EmailSchema,\n RoleSchema,\n SendVerificationEmailRequest,\n SendResetPasswordEmailRequest,\n ExchangeResetPasswordTokenRequest,\n VerifyEmailRequest,\n} from '@insforge/shared-schemas';\n\n/**\n * Dynamic profile type - represents flexible profile data from database\n * Fields can vary based on database schema configuration.\n * All fields are converted from snake_case (database) to camelCase (API)\n */\nexport type ProfileData = Record<string, any> & {\n id: string; // User ID (required)\n createdAt?: string; // PostgreSQL TIMESTAMPTZ\n updatedAt?: string; // PostgreSQL TIMESTAMPTZ\n};\n\n/**\n * Dynamic profile update type - for updating profile fields\n * Supports any fields that exist in the profile table\n */\nexport type UpdateProfileData = Partial<Record<string, any>>;\n\n/**\n * Convert database profile to include both snake_case and camelCase formats\n * Handles dynamic fields flexibly - automatically converts all snake_case keys to camelCase\n * \n * NOTE: Backward compatibility for <= v0.0.57\n * Both formats are returned to maintain compatibility with existing code.\n * For example: both created_at and createdAt are included in the result.\n */\nfunction convertDbProfileToCamelCase(dbProfile: Record<string, any>): ProfileData {\n const result: ProfileData = {\n id: dbProfile.id,\n };\n\n // Convert all fields - keep both snake_case and camelCase for backward compatibility (<= v0.0.57)\n Object.keys(dbProfile).forEach(key => {\n\n // Keep original field (snake_case) for backward compatibility (<= v0.0.57)\n result[key] = dbProfile[key];\n\n // Also add camelCase version if field contains underscore\n // e.g., created_at -> createdAt, avatar_url -> avatarUrl, etc.\n if (key.includes('_')) {\n const camelKey = key.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());\n result[camelKey] = dbProfile[key];\n }\n });\n\n return result;\n}\n\n/**\n * Convert camelCase profile data to database format (snake_case)\n * Handles dynamic fields flexibly - automatically converts all camelCase keys to snake_case\n */\nfunction convertCamelCaseToDbProfile(profile: UpdateProfileData): Record<string, any> {\n const dbProfile: Record<string, any> = {};\n\n Object.keys(profile).forEach(key => {\n if (profile[key] === undefined) return;\n\n // Convert camelCase to snake_case\n // e.g., avatarUrl -> avatar_url, firstName -> first_name\n const snakeKey = key.replace(/[A-Z]/g, letter => `_${letter.toLowerCase()}`);\n dbProfile[snakeKey] = profile[key];\n });\n\n return dbProfile;\n}\n\n/**\n * Check if current environment is a hosted auth environment\n * Returns true for:\n * - localhost with port 7130 (hosted auth app dev)\n * - https://*.insforge.app (hosted auth app production)\n */\nfunction isHostedAuthEnvironment(): boolean {\n if (typeof window === 'undefined') {\n return false;\n }\n\n const { hostname, port, protocol } = window.location;\n\n // Check for localhost:7130\n if (hostname === 'localhost' && port === '7130') {\n return true;\n }\n\n // Check for https://*.insforge.app\n if (protocol === 'https:' && hostname.endsWith('.insforge.app')) {\n return true;\n }\n\n return false;\n}\n\nexport class Auth {\n private database: Database;\n\n constructor(\n private http: HttpClient,\n private tokenManager: TokenManager\n ) {\n this.database = new Database(http, tokenManager);\n // Auto-detect OAuth callback parameters in the URL\n this.detectAuthCallback();\n }\n\n /**\n * Set the isAuthenticated cookie flag on the frontend domain\n * This is managed by SDK, not backend, to work in cross-origin scenarios\n */\n private setAuthenticatedCookie(): void {\n if (typeof document === 'undefined') return;\n // Set cookie with 7 days expiry, matching backend's refresh token lifetime\n const maxAge = 7 * 24 * 60 * 60; // 7 days in seconds\n document.cookie = `${AUTH_FLAG_COOKIE}=true; path=/; max-age=${maxAge}; SameSite=Lax`;\n }\n\n /**\n * Clear the isAuthenticated cookie flag from the frontend domain\n */\n private clearAuthenticatedCookie(): void {\n if (typeof document === 'undefined') return;\n document.cookie = `${AUTH_FLAG_COOKIE}=; path=/; max-age=0; SameSite=Lax`;\n }\n\n /**\n * Switch to SecureSessionStorage (cookie-based auth)\n * Called when backend returns sessionMode: 'secure'\n * @internal\n */\n _switchToSecureStorage(): void {\n console.log('[InsForge:Auth] _switchToSecureStorage() called, current strategy:', this.tokenManager.getStrategyId());\n if (this.tokenManager.getStrategyId() === 'secure') {\n console.log('[InsForge:Auth] _switchToSecureStorage() - already in secure mode, skipping');\n return;\n }\n\n const currentSession = this.tokenManager.getSession();\n this.tokenManager.setStrategy(new SecureSessionStorage());\n\n // Clear localStorage (no longer needed)\n if (typeof localStorage !== 'undefined') {\n console.log('[InsForge:Auth] _switchToSecureStorage() - clearing localStorage');\n localStorage.removeItem(TOKEN_KEY);\n localStorage.removeItem(USER_KEY);\n }\n\n // Set SDK-managed cookie flag for page reload detection\n console.log('[InsForge:Auth] _switchToSecureStorage() - setting isAuthenticated cookie');\n this.setAuthenticatedCookie();\n\n // Migrate session to new strategy (in-memory)\n if (currentSession) {\n this.tokenManager.saveSession(currentSession);\n }\n }\n\n /**\n * Switch to LocalSessionStorage (localStorage-based auth)\n * Called when cookie-based auth fails (fallback)\n * @internal\n */\n _switchToLocalStorage(): void {\n if (this.tokenManager.getStrategyId() === 'local') return;\n\n const currentSession = this.tokenManager.getSession();\n this.tokenManager.setStrategy(new LocalSessionStorage());\n\n // Clear SDK-managed cookie flag\n this.clearAuthenticatedCookie();\n\n // Migrate session to new strategy\n if (currentSession) {\n this.tokenManager.saveSession(currentSession);\n }\n }\n\n /**\n * Detect storage strategy based on backend response\n * @param sessionMode - The sessionMode returned by backend ('secure' or undefined)\n * @internal\n */\n private _detectStorageFromResponse(sessionMode?: string): void {\n console.log('[InsForge:Auth] _detectStorageFromResponse() - sessionMode:', sessionMode);\n if (sessionMode === 'secure') {\n this._switchToSecureStorage();\n } else {\n this._switchToLocalStorage();\n }\n }\n\n /**\n * Automatically detect and handle OAuth callback parameters in the URL\n * This runs on initialization to seamlessly complete the OAuth flow\n * Matches the backend's OAuth callback response (backend/src/api/routes/auth.ts:540-544)\n */\n detectAuthCallback(): void {\n // Only run in browser environment\n if (typeof window === 'undefined') return;\n\n try {\n const params = new URLSearchParams(window.location.search);\n\n // Backend returns: access_token, user_id, email, name (optional), session_mode\n const accessToken = params.get('access_token');\n const userId = params.get('user_id');\n const email = params.get('email');\n const name = params.get('name');\n const sessionMode = params.get('session_mode');\n\n // Check if we have OAuth callback parameters\n if (accessToken && userId && email) {\n // Detect backend storage mode from URL parameter FIRST (before saving session)\n this._detectStorageFromResponse(sessionMode || undefined);\n\n // Create session with the data from backend\n const session: AuthSession = {\n accessToken,\n user: {\n id: userId,\n email: email,\n name: name || '',\n // These fields are not provided by backend OAuth callback\n // They'll be populated when calling getCurrentUser()\n emailVerified: false,\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString(),\n } as any,\n };\n\n // Save session and set auth token\n this.tokenManager.saveSession(session);\n this.http.setAuthToken(accessToken);\n\n // Clean up the URL to remove sensitive parameters\n const url = new URL(window.location.href);\n url.searchParams.delete('access_token');\n url.searchParams.delete('user_id');\n url.searchParams.delete('email');\n url.searchParams.delete('name');\n url.searchParams.delete('session_mode');\n\n // Also handle error case from backend (line 581)\n if (params.has('error')) {\n url.searchParams.delete('error');\n }\n\n // Replace URL without adding to browser history\n window.history.replaceState({}, document.title, url.toString());\n }\n } catch (error) {\n // Silently continue - don't break initialization\n console.debug('OAuth callback detection skipped:', error);\n }\n }\n\n /**\n * Sign up a new user\n */\n async signUp(request: CreateUserRequest): Promise<{\n data: CreateUserResponse | null;\n error: InsForgeError | null;\n }> {\n try {\n const response = await this.http.post<CreateUserResponse>('/api/auth/users', request);\n\n // Detect storage mode from backend response FIRST (before saving session)\n // This ensures session is saved to the correct storage strategy\n const sessionMode = (response as any).sessionMode as string | undefined;\n this._detectStorageFromResponse(sessionMode);\n\n // Save session internally only if both accessToken and user exist\n if (response.accessToken && response.user) {\n const session: AuthSession = {\n accessToken: response.accessToken,\n user: response.user,\n };\n if (!isHostedAuthEnvironment()) {\n this.tokenManager.saveSession(session);\n }\n this.http.setAuthToken(response.accessToken);\n }\n\n return {\n data: response,\n error: null\n };\n } catch (error) {\n // Pass through API errors unchanged\n if (error instanceof InsForgeError) {\n return { data: null, error };\n }\n\n // Generic fallback for unexpected errors\n return {\n data: null,\n error: new InsForgeError(\n error instanceof Error ? error.message : 'An unexpected error occurred during sign up',\n 500,\n 'UNEXPECTED_ERROR'\n )\n };\n }\n }\n\n /**\n * Sign in with email and password\n */\n async signInWithPassword(request: CreateSessionRequest): Promise<{\n data: CreateSessionResponse | null;\n error: InsForgeError | null;\n }> {\n try {\n const response = await this.http.post<CreateSessionResponse>('/api/auth/sessions', request);\n\n // Detect storage mode from backend response FIRST (before saving session)\n const sessionMode = (response as any).sessionMode as string | undefined;\n this._detectStorageFromResponse(sessionMode);\n\n // Save session internally\n const session: AuthSession = {\n accessToken: response.accessToken || '',\n user: response.user || {\n id: '',\n email: '',\n name: '',\n emailVerified: false,\n createdAt: '',\n updatedAt: '',\n },\n };\n\n if (!isHostedAuthEnvironment()) {\n this.tokenManager.saveSession(session);\n }\n this.http.setAuthToken(response.accessToken || '');\n\n return {\n data: response,\n error: null\n };\n } catch (error) {\n // Pass through API errors unchanged\n if (error instanceof InsForgeError) {\n return { data: null, error };\n }\n\n // Generic fallback for unexpected errors\n return {\n data: null,\n error: new InsForgeError(\n 'An unexpected error occurred during sign in',\n 500,\n 'UNEXPECTED_ERROR'\n )\n };\n }\n }\n\n /**\n * Sign in with OAuth provider\n */\n async signInWithOAuth(options: {\n provider: OAuthProvidersSchema;\n redirectTo?: string;\n skipBrowserRedirect?: boolean;\n }): Promise<{\n data: { url?: string; provider?: string };\n error: InsForgeError | null;\n }> {\n try {\n const { provider, redirectTo, skipBrowserRedirect } = options;\n\n const params = redirectTo\n ? { redirect_uri: redirectTo }\n : undefined;\n\n const endpoint = `/api/auth/oauth/${provider}`;\n const response = await this.http.get<GetOauthUrlResponse>(endpoint, { params });\n\n // Automatically redirect in browser unless told not to\n if (typeof window !== 'undefined' && !skipBrowserRedirect) {\n window.location.href = response.authUrl;\n return { data: {}, error: null };\n }\n\n return {\n data: {\n url: response.authUrl,\n provider\n },\n error: null\n };\n } catch (error) {\n // Pass through API errors unchanged\n if (error instanceof InsForgeError) {\n return { data: {}, error };\n }\n\n // Generic fallback for unexpected errors\n return {\n data: {},\n error: new InsForgeError(\n 'An unexpected error occurred during OAuth initialization',\n 500,\n 'UNEXPECTED_ERROR'\n )\n };\n }\n }\n\n /**\n * Sign out the current user\n * In modern mode, also calls backend to clear the refresh token cookie\n */\n async signOut(): Promise<{ error: InsForgeError | null }> {\n // Log signOut call with stack trace for debugging\n console.log('[InsForge:Auth] signOut() called');\n console.log('[InsForge:Auth] signOut() stack trace:', new Error().stack);\n \n try {\n // If using secure storage, call backend to clear refresh token cookie\n if (this.tokenManager.getStrategyId() === 'secure') {\n console.log('[InsForge:Auth] signOut() - calling backend /api/auth/logout');\n try {\n await this.http.post('/api/auth/logout');\n console.log('[InsForge:Auth] signOut() - backend logout successful');\n } catch (e) {\n console.log('[InsForge:Auth] signOut() - backend logout failed (ignored):', e);\n // Ignore errors from logout endpoint - still clear local session\n }\n }\n\n this.tokenManager.clearSession();\n this.http.setAuthToken(null);\n\n // Clear SDK-managed isAuthenticated cookie (frontend domain)\n this.clearAuthenticatedCookie();\n console.log('[InsForge:Auth] signOut() - completed');\n\n return { error: null };\n } catch (error) {\n console.error('[InsForge:Auth] signOut() - error:', error);\n return {\n error: new InsForgeError(\n 'Failed to sign out',\n 500,\n 'SIGNOUT_ERROR'\n )\n };\n }\n }\n\n /**\n * Refresh the access token using the httpOnly refresh token cookie\n * Only works when backend supports secure session storage (httpOnly cookies)\n * \n * @returns New access token or throws an error\n */\n async refreshToken(): Promise<string> {\n console.log('[InsForge:Auth] refreshToken() called');\n try {\n const response = await this.http.post<{ accessToken: string; user?: any; sessionMode?: string }>(\n '/api/auth/refresh'\n );\n console.log('[InsForge:Auth] refreshToken() - response received, hasAccessToken:', !!response.accessToken);\n\n if (response.accessToken) {\n // Detect/confirm storage mode from backend response\n // This ensures we stay in secure mode after refresh\n this._detectStorageFromResponse(response.sessionMode);\n\n // Update token manager with new token\n this.tokenManager.setAccessToken(response.accessToken);\n this.http.setAuthToken(response.accessToken);\n\n // Update user data if provided\n if (response.user) {\n this.tokenManager.setUser(response.user);\n }\n\n console.log('[InsForge:Auth] refreshToken() - success');\n return response.accessToken;\n }\n\n throw new InsForgeError(\n 'No access token in refresh response',\n 500,\n 'REFRESH_FAILED'\n );\n } catch (error) {\n console.error('[InsForge:Auth] refreshToken() - error:', error);\n if (error instanceof InsForgeError) {\n // Handle 404 - backend doesn't support refresh endpoint (legacy backend)\n // Switch to localStorage mode for backward compatibility\n if (error.statusCode === 404) {\n console.log('[InsForge:Auth] refreshToken() - 404 detected, backend does not support refresh endpoint');\n console.log('[InsForge:Auth] refreshToken() - switching to LocalSessionStorage for backward compatibility');\n this._switchToLocalStorage();\n // Clear the isAuthenticated cookie since secure mode is not supported\n this.clearAuthenticatedCookie();\n }\n \n // Clear session on auth-related errors (401/403)\n if (error.statusCode === 401 || error.statusCode === 403) {\n console.log('[InsForge:Auth] refreshToken() - clearing session due to 401/403');\n this.tokenManager.clearSession();\n this.http.setAuthToken(null);\n // Clear SDK-managed cookie on auth failure\n this.clearAuthenticatedCookie();\n }\n throw error;\n }\n\n throw new InsForgeError(\n 'Token refresh failed',\n 500,\n 'REFRESH_FAILED'\n );\n }\n }\n\n\n /**\n * Get all public authentication configuration (OAuth + Email)\n * Returns both OAuth providers and email authentication settings in one request\n * This is a public endpoint that doesn't require authentication\n * \n * @returns Complete public authentication configuration including OAuth providers and email auth settings\n * \n * @example\n * ```ts\n * const { data, error } = await insforge.auth.getPublicAuthConfig();\n * if (data) {\n * console.log(`OAuth providers: ${data.oauth.data.length}`);\n * console.log(`Password min length: ${data.email.passwordMinLength}`);\n * }\n * ```\n */\n async getPublicAuthConfig(): Promise<{\n data: GetPublicAuthConfigResponse | null;\n error: InsForgeError | null;\n }> {\n try {\n const response = await this.http.get<GetPublicAuthConfigResponse>('/api/auth/public-config');\n\n return {\n data: response,\n error: null\n };\n } catch (error) {\n // Pass through API errors unchanged\n if (error instanceof InsForgeError) {\n return { data: null, error };\n }\n\n // Generic fallback for unexpected errors\n return {\n data: null,\n error: new InsForgeError(\n 'An unexpected error occurred while fetching public authentication configuration',\n 500,\n 'UNEXPECTED_ERROR'\n )\n };\n }\n }\n\n\n /**\n * Get the current user with full profile information\n * Returns both auth info (id, email, role) and profile data (dynamic fields from users table)\n * \n * In secure session mode (httpOnly cookie), this method will automatically attempt\n * to refresh the session if no access token is available (e.g., after page reload).\n */\n async getCurrentUser(): Promise<{\n data: {\n user: {\n id: UserIdSchema;\n email: EmailSchema;\n role: RoleSchema;\n };\n profile: ProfileData | null;\n } | null;\n error: any | null;\n }> {\n console.log('[InsForge:Auth] getCurrentUser() called');\n try {\n // Check if we have a token\n // Use getAccessToken() instead of getSession() to avoid requiring user data\n // This decouples token availability from cached user data\n let accessToken = this.tokenManager.getAccessToken();\n const shouldRefresh = this.tokenManager.shouldAttemptRefresh();\n console.log('[InsForge:Auth] getCurrentUser() - hasAccessToken:', !!accessToken, 'shouldAttemptRefresh:', shouldRefresh);\n\n // In secure mode, if no token in memory but auth cookie exists, try to refresh\n // This handles page reload scenario where access token was in memory only\n if (!accessToken && shouldRefresh) {\n console.log('[InsForge:Auth] getCurrentUser() - attempting refresh');\n try {\n accessToken = await this.refreshToken();\n } catch (error) {\n console.log('[InsForge:Auth] getCurrentUser() - refresh failed:', error);\n if (error instanceof InsForgeError && (error.statusCode === 401 || error.statusCode === 403)) {\n return { data: null, error: error };\n }\n return { data: null, error: error instanceof InsForgeError ? error : new InsForgeError('Token refresh failed', 500, 'REFRESH_FAILED') };\n }\n }\n\n if (!accessToken) {\n console.log('[InsForge:Auth] getCurrentUser() - no access token, returning null');\n return { data: null, error: null };\n }\n\n // Call the API for auth info\n this.http.setAuthToken(accessToken);\n console.log('[InsForge:Auth] getCurrentUser() - fetching user from API');\n const authResponse = await this.http.get<GetCurrentSessionResponse>('/api/auth/sessions/current');\n\n // Get the user's profile using query builder\n const { data: profile, error: profileError } = await this.database\n .from('users')\n .select('*')\n .eq('id', authResponse.user.id)\n .single();\n\n // For database errors, return PostgrestError directly\n if (profileError && (profileError as any).code !== 'PGRST116') { // PGRST116 = not found\n return { data: null, error: profileError };\n }\n\n console.log('[InsForge:Auth] getCurrentUser() - success');\n return {\n data: {\n user: authResponse.user,\n profile: profile ? convertDbProfileToCamelCase(profile) : null\n },\n error: null\n };\n } catch (error) {\n console.error('[InsForge:Auth] getCurrentUser() - catch error:', error);\n // If unauthorized, clear LOCAL session only - DO NOT call signOut() which would clear backend cookie!\n // This prevents accidentally clearing a valid refresh token due to expired access token\n if (error instanceof InsForgeError && error.statusCode === 401) {\n console.log('[InsForge:Auth] getCurrentUser() - 401 error, clearing local session only (NOT calling signOut)');\n this.tokenManager.clearSession();\n this.http.setAuthToken(null);\n this.clearAuthenticatedCookie();\n return { data: null, error: null };\n }\n\n // Pass through all other errors unchanged\n if (error instanceof InsForgeError) {\n return { data: null, error };\n }\n\n // Generic fallback for unexpected errors\n return {\n data: null,\n error: new InsForgeError(\n 'An unexpected error occurred while fetching user',\n 500,\n 'UNEXPECTED_ERROR'\n )\n };\n }\n }\n\n /**\n * Get any user's profile by ID\n * Returns profile information from the users table (dynamic fields)\n */\n async getProfile(userId: string): Promise<{\n data: ProfileData | null;\n error: any | null;\n }> {\n const { data, error } = await this.database\n .from('users')\n .select('*')\n .eq('id', userId)\n .single();\n\n // Handle not found as null, not error\n if (error && (error as any).code === 'PGRST116') {\n return { data: null, error: null };\n }\n\n // Convert database format to camelCase format\n if (data) {\n return { data: convertDbProfileToCamelCase(data), error: null };\n }\n\n // Return PostgrestError directly for database operations\n return { data: null, error };\n }\n\n /**\n * Get the current session (only session data, no API call)\n * Returns the stored JWT token and basic user info from local storage\n */\n getCurrentSession(): {\n data: { session: AuthSession | null };\n error: InsForgeError | null;\n } {\n try {\n const session = this.tokenManager.getSession();\n\n if (session?.accessToken) {\n this.http.setAuthToken(session.accessToken);\n return { data: { session }, error: null };\n }\n\n return { data: { session: null }, error: null };\n } catch (error) {\n // Pass through API errors unchanged\n if (error instanceof InsForgeError) {\n return { data: { session: null }, error };\n }\n\n // Generic fallback for unexpected errors\n return {\n data: { session: null },\n error: new InsForgeError(\n 'An unexpected error occurred while getting session',\n 500,\n 'UNEXPECTED_ERROR'\n )\n };\n }\n }\n\n /**\n * Set/Update the current user's profile\n * Updates profile information in the users table (supports any dynamic fields)\n */\n async setProfile(profile: UpdateProfileData): Promise<{\n data: ProfileData | null;\n error: any | null;\n }> {\n // Get current session to get user ID\n const session = this.tokenManager.getSession();\n if (!session?.accessToken) {\n return {\n data: null,\n error: new InsForgeError(\n 'No authenticated user found',\n 401,\n 'UNAUTHENTICATED'\n )\n };\n }\n\n // If no user ID in session (edge function scenario), fetch it\n if (!session.user?.id) {\n const { data, error } = await this.getCurrentUser();\n if (error) {\n return { data: null, error };\n }\n if (data?.user) {\n // Update session with minimal user info\n session.user = {\n id: data.user.id,\n email: data.user.email,\n name: '',\n emailVerified: false,\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString(),\n };\n this.tokenManager.saveSession(session);\n }\n }\n\n // Convert camelCase format to database format (snake_case)\n const dbProfile = convertCamelCaseToDbProfile(profile);\n\n // Update the profile using query builder\n const { data, error } = await this.database\n .from('users')\n .update(dbProfile)\n .eq('id', session.user.id)\n .select()\n .single();\n\n // Convert database format back to camelCase format\n if (data) {\n return { data: convertDbProfileToCamelCase(data), error: null };\n }\n\n // Return PostgrestError directly for database operations\n return { data: null, error };\n }\n\n /**\n * Send email verification (code or link based on config)\n *\n * Send email verification using the method configured in auth settings (verifyEmailMethod).\n * When method is 'code', sends a 6-digit numeric code. When method is 'link', sends a magic link.\n * Prevents user enumeration by returning success even if email doesn't exist.\n */\n async sendVerificationEmail(request: SendVerificationEmailRequest): Promise<{\n data: { success: boolean; message: string } | null;\n error: InsForgeError | null;\n }> {\n try {\n const response = await this.http.post<{ success: boolean; message: string }>(\n '/api/auth/email/send-verification',\n request\n );\n\n return {\n data: response,\n error: null\n };\n } catch (error) {\n // Pass through API errors unchanged\n if (error instanceof InsForgeError) {\n return { data: null, error };\n }\n\n // Generic fallback for unexpected errors\n return {\n data: null,\n error: new InsForgeError(\n 'An unexpected error occurred while sending verification code',\n 500,\n 'UNEXPECTED_ERROR'\n )\n };\n }\n }\n\n /**\n * Send password reset (code or link based on config)\n *\n * Send password reset email using the method configured in auth settings (resetPasswordMethod).\n * When method is 'code', sends a 6-digit numeric code for two-step flow.\n * When method is 'link', sends a magic link.\n * Prevents user enumeration by returning success even if email doesn't exist.\n */\n async sendResetPasswordEmail(request: SendResetPasswordEmailRequest): Promise<{\n data: { success: boolean; message: string } | null;\n error: InsForgeError | null;\n }> {\n try {\n const response = await this.http.post<{ success: boolean; message: string }>(\n '/api/auth/email/send-reset-password',\n request\n );\n\n return {\n data: response,\n error: null\n };\n } catch (error) {\n // Pass through API errors unchanged\n if (error instanceof InsForgeError) {\n return { data: null, error };\n }\n\n // Generic fallback for unexpected errors\n return {\n data: null,\n error: new InsForgeError(\n 'An unexpected error occurred while sending password reset code',\n 500,\n 'UNEXPECTED_ERROR'\n )\n };\n }\n }\n\n /**\n * Exchange reset password code for reset token\n *\n * Step 1 of two-step password reset flow (only used when resetPasswordMethod is 'code'):\n * 1. Verify the 6-digit code sent to user's email\n * 2. Return a reset token that can be used to actually reset the password\n *\n * This endpoint is not used when resetPasswordMethod is 'link' (magic link flow is direct).\n */\n async exchangeResetPasswordToken(request: ExchangeResetPasswordTokenRequest): Promise<{\n data: { token: string; expiresAt: string } | null;\n error: InsForgeError | null;\n }> {\n try {\n const response = await this.http.post<{ token: string; expiresAt: string }>(\n '/api/auth/email/exchange-reset-password-token',\n request\n );\n\n return {\n data: response,\n error: null\n };\n } catch (error) {\n // Pass through API errors unchanged\n if (error instanceof InsForgeError) {\n return { data: null, error };\n }\n\n // Generic fallback for unexpected errors\n return {\n data: null,\n error: new InsForgeError(\n 'An unexpected error occurred while verifying reset code',\n 500,\n 'UNEXPECTED_ERROR'\n )\n };\n }\n }\n\n /**\n * Reset password with token\n *\n * Reset user password with a token. The token can be:\n * - Magic link token (64-character hex token from send-reset-password when method is 'link')\n * - Reset token (from exchange-reset-password-token after code verification when method is 'code')\n *\n * Both token types use RESET_PASSWORD purpose and are verified the same way.\n *\n * Flow summary:\n * - Code method: send-reset-password → exchange-reset-password-token → reset-password (with resetToken)\n * - Link method: send-reset-password → reset-password (with link token directly)\n */\n async resetPassword(request: { newPassword: string; otp: string }): Promise<{\n data: { message: string; redirectTo?: string } | null;\n error: InsForgeError | null;\n }> {\n try {\n const response = await this.http.post<{ message: string; redirectTo?: string }>(\n '/api/auth/email/reset-password',\n request\n );\n\n return {\n data: response,\n error: null\n };\n } catch (error) {\n // Pass through API errors unchanged\n if (error instanceof InsForgeError) {\n return { data: null, error };\n }\n\n // Generic fallback for unexpected errors\n return {\n data: null,\n error: new InsForgeError(\n 'An unexpected error occurred while resetting password',\n 500,\n 'UNEXPECTED_ERROR'\n )\n };\n }\n }\n\n /**\n * Verify email with code or link\n *\n * Verify email address using the method configured in auth settings (verifyEmailMethod):\n * - Code verification: Provide both `email` and `otp` (6-digit numeric code)\n * - Link verification: Provide only `otp` (64-character hex token from magic link)\n *\n * Successfully verified users will receive a session token.\n *\n * The email verification link sent to users always points to the backend API endpoint.\n * If `verifyEmailRedirectTo` is configured, the backend will redirect to that URL after successful verification.\n * Otherwise, a default success page is displayed.\n */\n async verifyEmail(request: VerifyEmailRequest): Promise<{\n data: { accessToken: string; user?: any; redirectTo?: string } | null;\n error: InsForgeError | null;\n }> {\n try {\n const response = await this.http.post<{ accessToken: string; user?: any; redirectTo?: string; sessionMode?: string }>(\n '/api/auth/email/verify',\n request\n );\n\n // Detect storage mode from backend response FIRST (before saving session)\n const sessionMode = (response as any).sessionMode as string | undefined;\n this._detectStorageFromResponse(sessionMode);\n\n // Save session if we got a token\n if (response.accessToken) {\n const session: AuthSession = {\n accessToken: response.accessToken,\n user: response.user || {} as any,\n };\n this.tokenManager.saveSession(session);\n this.http.setAuthToken(response.accessToken);\n }\n\n return {\n data: response,\n error: null\n };\n } catch (error) {\n // Pass through API errors unchanged\n if (error instanceof InsForgeError) {\n return { data: null, error };\n }\n\n // Generic fallback for unexpected errors\n return {\n data: null,\n error: new InsForgeError(\n 'An unexpected error occurred while verifying email',\n 500,\n 'UNEXPECTED_ERROR'\n )\n };\n }\n }\n}","/**\r\n * Storage module for InsForge SDK\r\n * Handles file uploads, downloads, and bucket management\r\n */\r\n\r\nimport { HttpClient } from '../lib/http-client';\r\nimport { InsForgeError } from '../types';\r\nimport type { \r\n StorageFileSchema,\r\n ListObjectsResponseSchema\r\n} from '@insforge/shared-schemas';\r\n\r\nexport interface StorageResponse<T> {\r\n data: T | null;\r\n error: InsForgeError | null;\r\n}\r\n\r\ninterface UploadStrategy {\r\n method: 'direct' | 'presigned';\r\n uploadUrl: string;\r\n fields?: Record<string, string>;\r\n key: string;\r\n confirmRequired: boolean;\r\n confirmUrl?: string;\r\n expiresAt?: Date;\r\n}\r\n\r\ninterface DownloadStrategy {\r\n method: 'direct' | 'presigned';\r\n url: string;\r\n expiresAt?: Date;\r\n}\r\n\r\n/**\r\n * Storage bucket operations\r\n */\r\nexport class StorageBucket {\r\n constructor(\r\n private bucketName: string,\r\n private http: HttpClient\r\n ) {}\r\n\r\n /**\r\n * Upload a file with a specific key\r\n * Uses the upload strategy from backend (direct or presigned)\r\n * @param path - The object key/path\r\n * @param file - File or Blob to upload\r\n */\r\n async upload(\r\n path: string,\r\n file: File | Blob\r\n ): Promise<StorageResponse<StorageFileSchema>> {\r\n try {\r\n // Get upload strategy from backend - this is required\r\n const strategyResponse = await this.http.post<UploadStrategy>(\r\n `/api/storage/buckets/${this.bucketName}/upload-strategy`,\r\n {\r\n filename: path,\r\n contentType: file.type || 'application/octet-stream',\r\n size: file.size\r\n }\r\n );\r\n\r\n // Use presigned URL if available\r\n if (strategyResponse.method === 'presigned') {\r\n return await this.uploadWithPresignedUrl(strategyResponse, file);\r\n }\r\n\r\n // Use direct upload if strategy says so\r\n if (strategyResponse.method === 'direct') {\r\n const formData = new FormData();\r\n formData.append('file', file);\r\n\r\n const response = await this.http.request<StorageFileSchema>(\r\n 'PUT',\r\n `/api/storage/buckets/${this.bucketName}/objects/${encodeURIComponent(path)}`,\r\n {\r\n body: formData as any,\r\n headers: {\r\n // Don't set Content-Type, let browser set multipart boundary\r\n }\r\n }\r\n );\r\n\r\n return { data: response, error: null };\r\n }\r\n\r\n throw new InsForgeError(\r\n `Unsupported upload method: ${strategyResponse.method}`,\r\n 500,\r\n 'STORAGE_ERROR'\r\n );\r\n } catch (error) {\r\n return { \r\n data: null, \r\n error: error instanceof InsForgeError ? error : new InsForgeError(\r\n 'Upload failed',\r\n 500,\r\n 'STORAGE_ERROR'\r\n )\r\n };\r\n }\r\n }\r\n\r\n /**\r\n * Upload a file with auto-generated key\r\n * Uses the upload strategy from backend (direct or presigned)\r\n * @param file - File or Blob to upload\r\n */\r\n async uploadAuto(\r\n file: File | Blob\r\n ): Promise<StorageResponse<StorageFileSchema>> {\r\n try {\r\n const filename = file instanceof File ? file.name : 'file';\r\n \r\n // Get upload strategy from backend - this is required\r\n const strategyResponse = await this.http.post<UploadStrategy>(\r\n `/api/storage/buckets/${this.bucketName}/upload-strategy`,\r\n {\r\n filename,\r\n contentType: file.type || 'application/octet-stream',\r\n size: file.size\r\n }\r\n );\r\n\r\n // Use presigned URL if available\r\n if (strategyResponse.method === 'presigned') {\r\n return await this.uploadWithPresignedUrl(strategyResponse, file);\r\n }\r\n\r\n // Use direct upload if strategy says so\r\n if (strategyResponse.method === 'direct') {\r\n const formData = new FormData();\r\n formData.append('file', file);\r\n\r\n const response = await this.http.request<StorageFileSchema>(\r\n 'POST',\r\n `/api/storage/buckets/${this.bucketName}/objects`,\r\n {\r\n body: formData as any,\r\n headers: {\r\n // Don't set Content-Type, let browser set multipart boundary\r\n }\r\n }\r\n );\r\n\r\n return { data: response, error: null };\r\n }\r\n\r\n throw new InsForgeError(\r\n `Unsupported upload method: ${strategyResponse.method}`,\r\n 500,\r\n 'STORAGE_ERROR'\r\n );\r\n } catch (error) {\r\n return { \r\n data: null, \r\n error: error instanceof InsForgeError ? error : new InsForgeError(\r\n 'Upload failed',\r\n 500,\r\n 'STORAGE_ERROR'\r\n )\r\n };\r\n }\r\n }\r\n\r\n /**\r\n * Internal method to handle presigned URL uploads\r\n */\r\n private async uploadWithPresignedUrl(\r\n strategy: UploadStrategy,\r\n file: File | Blob\r\n ): Promise<StorageResponse<StorageFileSchema>> {\r\n try {\r\n // Upload to presigned URL (e.g., S3)\r\n const formData = new FormData();\r\n \r\n // Add all fields from the presigned URL\r\n if (strategy.fields) {\r\n Object.entries(strategy.fields).forEach(([key, value]) => {\r\n formData.append(key, value);\r\n });\r\n }\r\n \r\n // File must be the last field for S3\r\n formData.append('file', file);\r\n\r\n const uploadResponse = await fetch(strategy.uploadUrl, {\r\n method: 'POST',\r\n body: formData\r\n });\r\n\r\n if (!uploadResponse.ok) {\r\n throw new InsForgeError(\r\n `Upload to storage failed: ${uploadResponse.statusText}`,\r\n uploadResponse.status,\r\n 'STORAGE_ERROR'\r\n );\r\n }\r\n\r\n // Confirm upload with backend if required\r\n if (strategy.confirmRequired && strategy.confirmUrl) {\r\n const confirmResponse = await this.http.post<StorageFileSchema>(\r\n strategy.confirmUrl,\r\n {\r\n size: file.size,\r\n contentType: file.type || 'application/octet-stream'\r\n }\r\n );\r\n\r\n return { data: confirmResponse, error: null };\r\n }\r\n\r\n // If no confirmation required, return basic file info\r\n return {\r\n data: {\r\n key: strategy.key,\r\n bucket: this.bucketName,\r\n size: file.size,\r\n mimeType: file.type || 'application/octet-stream',\r\n uploadedAt: new Date().toISOString(),\r\n url: this.getPublicUrl(strategy.key)\r\n } as StorageFileSchema,\r\n error: null\r\n };\r\n } catch (error) {\r\n throw error instanceof InsForgeError ? error : new InsForgeError(\r\n 'Presigned upload failed',\r\n 500,\r\n 'STORAGE_ERROR'\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Download a file\r\n * Uses the download strategy from backend (direct or presigned)\r\n * @param path - The object key/path\r\n * Returns the file as a Blob\r\n */\r\n async download(path: string): Promise<{ data: Blob | null; error: InsForgeError | null }> {\r\n try {\r\n // Get download strategy from backend - this is required\r\n const strategyResponse = await this.http.post<DownloadStrategy>(\r\n `/api/storage/buckets/${this.bucketName}/objects/${encodeURIComponent(path)}/download-strategy`,\r\n { expiresIn: 3600 }\r\n );\r\n\r\n // Use URL from strategy\r\n const downloadUrl = strategyResponse.url;\r\n \r\n // Download from the URL\r\n const headers: HeadersInit = {};\r\n \r\n // Only add auth header for direct downloads (not presigned URLs)\r\n if (strategyResponse.method === 'direct') {\r\n Object.assign(headers, this.http.getHeaders());\r\n }\r\n \r\n const response = await fetch(downloadUrl, {\r\n method: 'GET',\r\n headers\r\n });\r\n\r\n if (!response.ok) {\r\n try {\r\n const error = await response.json();\r\n throw InsForgeError.fromApiError(error);\r\n } catch {\r\n throw new InsForgeError(\r\n `Download failed: ${response.statusText}`,\r\n response.status,\r\n 'STORAGE_ERROR'\r\n );\r\n }\r\n }\r\n\r\n const blob = await response.blob();\r\n return { data: blob, error: null };\r\n } catch (error) {\r\n return { \r\n data: null, \r\n error: error instanceof InsForgeError ? error : new InsForgeError(\r\n 'Download failed',\r\n 500,\r\n 'STORAGE_ERROR'\r\n )\r\n };\r\n }\r\n }\r\n\r\n /**\r\n * Get public URL for a file\r\n * @param path - The object key/path\r\n */\r\n getPublicUrl(path: string): string {\r\n return `${this.http.baseUrl}/api/storage/buckets/${this.bucketName}/objects/${encodeURIComponent(path)}`;\r\n }\r\n\r\n /**\r\n * List objects in the bucket\r\n * @param prefix - Filter by key prefix\r\n * @param search - Search in file names\r\n * @param limit - Maximum number of results (default: 100, max: 1000)\r\n * @param offset - Number of results to skip\r\n */\r\n async list(options?: {\r\n prefix?: string;\r\n search?: string;\r\n limit?: number;\r\n offset?: number;\r\n }): Promise<StorageResponse<ListObjectsResponseSchema>> {\r\n try {\r\n const params: Record<string, string> = {};\r\n \r\n if (options?.prefix) params.prefix = options.prefix;\r\n if (options?.search) params.search = options.search;\r\n if (options?.limit) params.limit = options.limit.toString();\r\n if (options?.offset) params.offset = options.offset.toString();\r\n\r\n const response = await this.http.get<ListObjectsResponseSchema>(\r\n `/api/storage/buckets/${this.bucketName}/objects`,\r\n { params }\r\n );\r\n\r\n return { data: response, error: null };\r\n } catch (error) {\r\n return { \r\n data: null, \r\n error: error instanceof InsForgeError ? error : new InsForgeError(\r\n 'List failed',\r\n 500,\r\n 'STORAGE_ERROR'\r\n )\r\n };\r\n }\r\n }\r\n\r\n /**\r\n * Delete a file\r\n * @param path - The object key/path\r\n */\r\n async remove(path: string): Promise<StorageResponse<{ message: string }>> {\r\n try {\r\n const response = await this.http.delete<{ message: string }>(\r\n `/api/storage/buckets/${this.bucketName}/objects/${encodeURIComponent(path)}`\r\n );\r\n\r\n return { data: response, error: null };\r\n } catch (error) {\r\n return { \r\n data: null, \r\n error: error instanceof InsForgeError ? error : new InsForgeError(\r\n 'Delete failed',\r\n 500,\r\n 'STORAGE_ERROR'\r\n )\r\n };\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Storage module for file operations\r\n */\r\nexport class Storage {\r\n constructor(private http: HttpClient) {}\r\n\r\n /**\r\n * Get a bucket instance for operations\r\n * @param bucketName - Name of the bucket\r\n */\r\n from(bucketName: string): StorageBucket {\r\n return new StorageBucket(bucketName, this.http);\r\n }\r\n}","/**\r\n * AI Module for Insforge SDK\r\n * Response format roughly matches OpenAI SDK for compatibility\r\n *\r\n * The backend handles all the complexity of different AI providers\r\n * and returns a unified format. This SDK transforms responses to match OpenAI-like format.\r\n */\r\n\r\nimport { HttpClient } from \"../lib/http-client\";\r\nimport {\r\n ChatCompletionRequest,\r\n ChatCompletionResponse,\r\n ImageGenerationRequest,\r\n ImageGenerationResponse,\r\n} from \"@insforge/shared-schemas\";\r\n\r\nexport class AI {\r\n public readonly chat: Chat;\r\n public readonly images: Images;\r\n\r\n constructor(private http: HttpClient) {\r\n this.chat = new Chat(http);\r\n this.images = new Images(http);\r\n }\r\n}\r\n\r\nclass Chat {\r\n public readonly completions: ChatCompletions;\r\n\r\n constructor(http: HttpClient) {\r\n this.completions = new ChatCompletions(http);\r\n }\r\n}\r\n\r\nclass ChatCompletions {\r\n constructor(private http: HttpClient) {}\r\n\r\n /**\r\n * Create a chat completion - OpenAI-like response format\r\n *\r\n * @example\r\n * ```typescript\r\n * // Non-streaming\r\n * const completion = await client.ai.chat.completions.create({\r\n * model: 'gpt-4',\r\n * messages: [{ role: 'user', content: 'Hello!' }]\r\n * });\r\n * console.log(completion.choices[0].message.content);\r\n *\r\n * // With images\r\n * const response = await client.ai.chat.completions.create({\r\n * model: 'gpt-4-vision',\r\n * messages: [{\r\n * role: 'user',\r\n * content: 'What is in this image?',\r\n * images: [{ url: 'https://example.com/image.jpg' }]\r\n * }]\r\n * });\r\n *\r\n * // Streaming - returns async iterable\r\n * const stream = await client.ai.chat.completions.create({\r\n * model: 'gpt-4',\r\n * messages: [{ role: 'user', content: 'Tell me a story' }],\r\n * stream: true\r\n * });\r\n *\r\n * for await (const chunk of stream) {\r\n * if (chunk.choices[0]?.delta?.content) {\r\n * process.stdout.write(chunk.choices[0].delta.content);\r\n * }\r\n * }\r\n * ```\r\n */\r\n async create(params: ChatCompletionRequest): Promise<any> {\r\n // Backend already expects camelCase, no transformation needed\r\n const backendParams = {\r\n model: params.model,\r\n messages: params.messages,\r\n temperature: params.temperature,\r\n maxTokens: params.maxTokens,\r\n topP: params.topP,\r\n stream: params.stream,\r\n };\r\n\r\n // For streaming, return an async iterable that yields OpenAI-like chunks\r\n if (params.stream) {\r\n const headers = this.http.getHeaders();\r\n headers[\"Content-Type\"] = \"application/json\";\r\n\r\n const response = await this.http.fetch(\r\n `${this.http.baseUrl}/api/ai/chat/completion`,\r\n {\r\n method: \"POST\",\r\n headers,\r\n body: JSON.stringify(backendParams),\r\n }\r\n );\r\n\r\n if (!response.ok) {\r\n const error = await response.json();\r\n throw new Error(error.error || \"Stream request failed\");\r\n }\r\n\r\n // Return async iterable that parses SSE and transforms to OpenAI-like format\r\n return this.parseSSEStream(response, params.model);\r\n }\r\n\r\n // Non-streaming: transform response to OpenAI-like format\r\n const response: ChatCompletionResponse = await this.http.post(\r\n \"/api/ai/chat/completion\",\r\n backendParams\r\n );\r\n\r\n // Transform to OpenAI-like format\r\n const content = response.text || \"\";\r\n\r\n return {\r\n id: `chatcmpl-${Date.now()}`,\r\n object: \"chat.completion\",\r\n created: Math.floor(Date.now() / 1000),\r\n model: response.metadata?.model,\r\n choices: [\r\n {\r\n index: 0,\r\n message: {\r\n role: \"assistant\",\r\n content,\r\n },\r\n finish_reason: \"stop\",\r\n },\r\n ],\r\n usage: response.metadata?.usage || {\r\n prompt_tokens: 0,\r\n completion_tokens: 0,\r\n total_tokens: 0,\r\n },\r\n };\r\n }\r\n\r\n /**\r\n * Parse SSE stream into async iterable of OpenAI-like chunks\r\n */\r\n private async *parseSSEStream(\r\n response: Response,\r\n model: string\r\n ): AsyncIterableIterator<any> {\r\n const reader = response.body!.getReader();\r\n const decoder = new TextDecoder();\r\n let buffer = \"\";\r\n\r\n try {\r\n while (true) {\r\n const { done, value } = await reader.read();\r\n if (done) break;\r\n\r\n buffer += decoder.decode(value, { stream: true });\r\n const lines = buffer.split(\"\\n\");\r\n buffer = lines.pop() || \"\";\r\n\r\n for (const line of lines) {\r\n if (line.startsWith(\"data: \")) {\r\n const dataStr = line.slice(6).trim();\r\n if (dataStr) {\r\n try {\r\n const data = JSON.parse(dataStr);\r\n\r\n // Transform to OpenAI-like streaming format\r\n if (data.chunk || data.content) {\r\n yield {\r\n id: `chatcmpl-${Date.now()}`,\r\n object: \"chat.completion.chunk\",\r\n created: Math.floor(Date.now() / 1000),\r\n model,\r\n choices: [\r\n {\r\n index: 0,\r\n delta: {\r\n content: data.chunk || data.content,\r\n },\r\n finish_reason: data.done ? \"stop\" : null,\r\n },\r\n ],\r\n };\r\n }\r\n\r\n // If we received the done signal, we can stop\r\n if (data.done) {\r\n reader.releaseLock();\r\n return;\r\n }\r\n } catch (e) {\r\n // Skip invalid JSON\r\n console.warn(\"Failed to parse SSE data:\", dataStr);\r\n }\r\n }\r\n }\r\n }\r\n }\r\n } finally {\r\n reader.releaseLock();\r\n }\r\n }\r\n}\r\n\r\nclass Images {\r\n constructor(private http: HttpClient) {}\r\n\r\n /**\r\n * Generate images - OpenAI-like response format\r\n *\r\n * @example\r\n * ```typescript\r\n * // Text-to-image\r\n * const response = await client.ai.images.generate({\r\n * model: 'dall-e-3',\r\n * prompt: 'A sunset over mountains',\r\n * });\r\n * console.log(response.images[0].url);\r\n *\r\n * // Image-to-image (with input images)\r\n * const response = await client.ai.images.generate({\r\n * model: 'stable-diffusion-xl',\r\n * prompt: 'Transform this into a watercolor painting',\r\n * images: [\r\n * { url: 'https://example.com/input.jpg' },\r\n * // or base64-encoded Data URI:\r\n * { url: 'data:image/jpeg;base64,/9j/4AAQ...' }\r\n * ]\r\n * });\r\n * ```\r\n */\r\n async generate(params: ImageGenerationRequest): Promise<any> {\r\n const response: ImageGenerationResponse = await this.http.post(\r\n \"/api/ai/image/generation\",\r\n params\r\n );\r\n \r\n // Build data array based on response content\r\n let data: Array<{ b64_json?: string; content?: string }> = [];\r\n \r\n if (response.images && response.images.length > 0) {\r\n // Has images - extract base64 and include text\r\n data = response.images.map(img => ({\r\n b64_json: img.imageUrl.replace(/^data:image\\/\\w+;base64,/, ''),\r\n content: response.text\r\n }));\r\n } else if (response.text) {\r\n // Text-only response\r\n data = [{ content: response.text }];\r\n }\r\n \r\n // Return OpenAI-compatible format\r\n return {\r\n created: Math.floor(Date.now() / 1000),\r\n data,\r\n ...(response.metadata?.usage && {\r\n usage: {\r\n total_tokens: response.metadata.usage.totalTokens || 0,\r\n input_tokens: response.metadata.usage.promptTokens || 0,\r\n output_tokens: response.metadata.usage.completionTokens || 0,\r\n }\r\n })\r\n };\r\n }\r\n}\r\n","import { HttpClient } from '../lib/http-client';\r\n\r\nexport interface FunctionInvokeOptions {\r\n /**\r\n * The body of the request\r\n */\r\n body?: any;\r\n \r\n /**\r\n * Custom headers to send with the request\r\n */\r\n headers?: Record<string, string>;\r\n \r\n /**\r\n * HTTP method (default: POST)\r\n */\r\n method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';\r\n}\r\n\r\n/**\r\n * Edge Functions client for invoking serverless functions\r\n * \r\n * @example\r\n * ```typescript\r\n * // Invoke a function with JSON body\r\n * const { data, error } = await client.functions.invoke('hello-world', {\r\n * body: { name: 'World' }\r\n * });\r\n * \r\n * // GET request\r\n * const { data, error } = await client.functions.invoke('get-data', {\r\n * method: 'GET'\r\n * });\r\n * ```\r\n */\r\nexport class Functions {\r\n private http: HttpClient;\r\n\r\n constructor(http: HttpClient) {\r\n this.http = http;\r\n }\r\n\r\n /**\r\n * Invokes an Edge Function\r\n * @param slug The function slug to invoke\r\n * @param options Request options\r\n */\r\n async invoke<T = any>(\r\n slug: string,\r\n options: FunctionInvokeOptions = {}\r\n ): Promise<{ data: T | null; error: Error | null }> {\r\n try {\r\n const { method = 'POST', body, headers = {} } = options;\r\n \r\n // Simple path: /functions/{slug}\r\n const path = `/functions/${slug}`;\r\n \r\n // Use the HTTP client's request method\r\n const data = await this.http.request<T>(\r\n method,\r\n path,\r\n { body, headers }\r\n );\r\n \r\n return { data, error: null };\r\n } catch (error: any) {\r\n // The HTTP client throws InsForgeError with all properties from the response\r\n // including error, message, details, statusCode, etc.\r\n // We need to preserve all of that information\r\n return { \r\n data: null, \r\n error: error // Pass through the full error object with all properties\r\n };\r\n }\r\n }\r\n}","import { InsForgeConfig } from './types';\r\nimport { HttpClient } from './lib/http-client';\r\nimport { TokenManager } from './lib/token-manager';\r\nimport { SecureSessionStorage, AUTH_FLAG_COOKIE } from './lib/session-storage';\r\nimport { Auth } from './modules/auth';\r\nimport { Database } from './modules/database-postgrest';\r\nimport { Storage } from './modules/storage';\r\nimport { AI } from './modules/ai';\r\nimport { Functions } from './modules/functions';\r\n\r\n/**\r\n * Check if the isAuthenticated cookie flag exists (SDK-managed on frontend domain)\r\n * This indicates a previous secure session was established and we should use SecureSessionStorage\r\n */\r\nfunction hasAuthenticatedCookie(): boolean {\r\n if (typeof document === 'undefined') return false;\r\n return document.cookie.split(';').some(c =>\r\n c.trim().startsWith(`${AUTH_FLAG_COOKIE}=`)\r\n );\r\n}\r\n\r\n/**\r\n * Main InsForge SDK Client\r\n * \r\n * @example\r\n * ```typescript\r\n * import { InsForgeClient } from '@insforge/sdk';\r\n * \r\n * const client = new InsForgeClient({\r\n * baseUrl: 'http://localhost:7130'\r\n * });\r\n * \r\n * // Authentication\r\n * const { data, error } = await client.auth.signUp({\r\n * email: 'user@example.com',\r\n * password: 'password123',\r\n * name: 'John Doe'\r\n * });\r\n * \r\n * // Database operations\r\n * const { data, error } = await client.database\r\n * .from('posts')\r\n * .select('*')\r\n * .eq('user_id', session.user.id)\r\n * .order('created_at', { ascending: false })\r\n * .limit(10);\r\n * \r\n * // Insert data\r\n * const { data: newPost } = await client.database\r\n * .from('posts')\r\n * .insert({ title: 'Hello', content: 'World' })\r\n * .single();\r\n * \r\n * // Invoke edge functions\r\n * const { data, error } = await client.functions.invoke('my-function', {\r\n * body: { message: 'Hello from SDK' }\r\n * });\r\n * ```\r\n */\r\nexport class InsForgeClient {\r\n private http: HttpClient;\r\n private tokenManager: TokenManager;\r\n public readonly auth: Auth;\r\n public readonly database: Database;\r\n public readonly storage: Storage;\r\n public readonly ai: AI;\r\n public readonly functions: Functions;\r\n\r\n constructor(config: InsForgeConfig = {}) {\r\n console.log('[InsForge:Client] Initializing SDK');\r\n this.http = new HttpClient(config);\r\n this.tokenManager = new TokenManager(config.storage);\r\n\r\n // Detect storage strategy based on SDK-managed cookie flag (on frontend domain)\r\n // If isAuthenticated cookie exists, a previous secure session was established\r\n const hasAuthCookie = hasAuthenticatedCookie();\r\n console.log('[InsForge:Client] hasAuthenticatedCookie:', hasAuthCookie);\r\n console.log('[InsForge:Client] document.cookie:', typeof document !== 'undefined' ? document.cookie : 'N/A (SSR)');\r\n \r\n if (hasAuthCookie) {\r\n console.log('[InsForge:Client] Switching to SecureSessionStorage');\r\n this.tokenManager.setStrategy(new SecureSessionStorage());\r\n }\r\n // Otherwise, keep default LocalSessionStorage (will switch if backend returns sessionMode: 'secure')\r\n\r\n // Check for edge function token\r\n if (config.edgeFunctionToken) {\r\n this.http.setAuthToken(config.edgeFunctionToken);\r\n // Save to token manager so getCurrentUser() works\r\n this.tokenManager.saveSession({\r\n accessToken: config.edgeFunctionToken,\r\n user: {} as any, // Will be populated by getCurrentUser()\r\n });\r\n }\r\n\r\n // Set up refresh callback for auto-refresh on 401\r\n // On 401, if refresh fails and we're using SecureSessionStorage, \r\n // fall back to LocalSessionStorage\r\n this.http.setRefreshCallback(async () => {\r\n console.log('[InsForge:Client] HTTP 401 refresh callback triggered');\r\n try {\r\n return await this.auth.refreshToken();\r\n } catch (e) {\r\n console.log('[InsForge:Client] Refresh callback failed:', e);\r\n // If refresh failed and we're in secure mode, cookie might be invalid\r\n // Fall back to localStorage mode\r\n if (this.tokenManager.getStrategyId() === 'secure') {\r\n console.log('[InsForge:Client] Falling back to LocalSessionStorage');\r\n this.auth._switchToLocalStorage();\r\n }\r\n return null;\r\n }\r\n });\r\n\r\n // Check for existing session\r\n // In secure mode: try to refresh to get access token\r\n // In local mode: check localStorage\r\n const existingSession = this.tokenManager.getSession();\r\n console.log('[InsForge:Client] existingSession:', !!existingSession, 'strategyId:', this.tokenManager.getStrategyId());\r\n \r\n if (existingSession?.accessToken) {\r\n this.http.setAuthToken(existingSession.accessToken);\r\n } else if (this.tokenManager.getStrategyId() === 'secure') {\r\n // Secure mode but no session in memory - need to refresh\r\n // This happens on page reload with cookie auth\r\n // Will be handled by first API call triggering 401 -> refresh\r\n console.log('[InsForge:Client] Secure mode, no session in memory - will refresh on first API call');\r\n }\r\n\r\n this.auth = new Auth(this.http, this.tokenManager);\r\n this.database = new Database(this.http, this.tokenManager);\r\n this.storage = new Storage(this.http);\r\n this.ai = new AI(this.http);\r\n this.functions = new Functions(this.http);\r\n console.log('[InsForge:Client] SDK initialized');\r\n }\r\n\r\n /**\r\n * Get the underlying HTTP client for custom requests\r\n * \r\n * @example\r\n * ```typescript\r\n * const httpClient = client.getHttpClient();\r\n * const customData = await httpClient.get('/api/custom-endpoint');\r\n * ```\r\n */\r\n getHttpClient(): HttpClient {\r\n return this.http;\r\n }\r\n\r\n /**\r\n * Get the current storage strategy identifier\r\n */\r\n getStorageStrategy(): string {\r\n return this.tokenManager.getStrategyId();\r\n }\r\n\r\n /**\r\n * Future modules will be added here:\r\n * - database: Database operations\r\n * - storage: File storage operations\r\n * - functions: Serverless functions\r\n * - tables: Table management\r\n * - metadata: Backend metadata\r\n */\r\n}\r\n"],"mappings":"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","names":["data","error","response"]}
|