@nhost/nhost-js 4.3.0 → 4.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("../refreshSession-Bw715ZmX.cjs"),t=e=>e.startsWith("{")&&e.endsWith("}"),s=e=>e&&"{}"!==e?e.slice(1,-1).split(",").map((e=>e.trim().replace(/^"(.*)"$/,"$1"))):[],o="nhostSession";class r{storageKey;constructor(e){this.storageKey=e?.storageKey||o}get(){try{const e=window.localStorage.getItem(this.storageKey);return e?JSON.parse(e):null}catch{return this.remove(),null}}set(e){window.localStorage.setItem(this.storageKey,JSON.stringify(e))}remove(){window.localStorage.removeItem(this.storageKey)}}class i{session=null;get(){return this.session}set(e){this.session=e}remove(){this.session=null}}exports.refreshSession=e.refreshSession,exports.CookieStorage=class{cookieName;expirationDays;secure;sameSite;constructor(e){this.cookieName=e?.cookieName||o,this.expirationDays=e?.expirationDays??30,this.secure=e?.secure??!0,this.sameSite=e?.sameSite||"lax"}get(){const e=document.cookie.split(";");for(const t of e){const[e,s]=t.trim().split("=");if(e===this.cookieName)try{return JSON.parse(decodeURIComponent(s||""))}catch{return this.remove(),null}}return null}set(e){const t=new Date;t.setTime(t.getTime()+24*this.expirationDays*60*60*1e3);const s=encodeURIComponent(JSON.stringify(e)),o=`${this.cookieName}=${s}; expires=${t.toUTCString()}; path=/; ${this.secure?"secure; ":""}SameSite=${this.sameSite}`;document.cookie=o}remove(){document.cookie=`${this.cookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; ${this.secure?"secure; ":""}SameSite=${this.sameSite}`}},exports.DEFAULT_SESSION_KEY=o,exports.LocalStorage=r,exports.MemoryStorage=i,exports.SessionStorage=class{storage;subscribers=new Set;constructor(e){this.storage=e}get(){return this.storage.get()}set(e){const o=(e=>{const o=e.split(".");if(3!==o.length||!o[1])throw new Error("Invalid access token format");const r=JSON.parse("undefined"!=typeof atob?atob(o[1]):Buffer.from(o[1],"base64").toString("utf-8")),i="number"==typeof r.iat?1e3*r.iat:void 0,n="number"==typeof r.exp?1e3*r.exp:void 0,a=r["https://hasura.io/jwt/claims"],c=a?Object.entries(a).reduce(((e,[o,r])=>("string"==typeof r&&t(r)?e[o]=s(r):e[o]=r,e)),{}):void 0;return{...r,iat:i,exp:n,"https://hasura.io/jwt/claims":c}})(e.accessToken),r={...e,decodedToken:o};this.storage.set(r),this.notifySubscribers(r)}remove(){this.storage.remove(),this.notifySubscribers(null)}onChange(e){return this.subscribers.add(e),()=>{this.subscribers.delete(e)}}notifySubscribers(e){for(const s of this.subscribers)try{s(e)}catch(t){console.error("Error notifying subscriber:",t)}}},exports.detectStorage=()=>"undefined"!=typeof window?new r:new i;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("../refreshSession-Bw715ZmX.cjs"),t=e=>{const t=e.split(".");if(3!==t.length||!t[1])throw new Error("Invalid access token format");const r=JSON.parse((e=>{let t=e.replace(/-/g,"+").replace(/_/g,"/");const s=t.length%4;s&&(t+="=".repeat(4-s));const o=atob(t),r=Uint8Array.from(o,(e=>e.charCodeAt(0)));return(new TextDecoder).decode(r)})(t[1])),i="number"==typeof r.iat?1e3*r.iat:void 0,n="number"==typeof r.exp?1e3*r.exp:void 0,a=r["https://hasura.io/jwt/claims"],c=a?Object.entries(a).reduce(((e,[t,r])=>("string"==typeof r&&s(r)?e[t]=o(r):e[t]=r,e)),{}):void 0;return{...r,iat:i,exp:n,"https://hasura.io/jwt/claims":c}},s=e=>e.startsWith("{")&&e.endsWith("}"),o=e=>e&&"{}"!==e?e.slice(1,-1).split(",").map((e=>e.trim().replace(/^"(.*)"$/,"$1"))):[],r="nhostSession";class i{storageKey;constructor(e){this.storageKey=e?.storageKey||r}get(){try{const e=window.localStorage.getItem(this.storageKey);return e?JSON.parse(e):null}catch{return this.remove(),null}}set(e){window.localStorage.setItem(this.storageKey,JSON.stringify(e))}remove(){window.localStorage.removeItem(this.storageKey)}}class n{session=null;get(){return this.session}set(e){this.session=e}remove(){this.session=null}}exports.refreshSession=e.refreshSession,exports.CookieStorage=class{cookieName;expirationDays;secure;sameSite;constructor(e){this.cookieName=e?.cookieName||r,this.expirationDays=e?.expirationDays??30,this.secure=e?.secure??!0,this.sameSite=e?.sameSite||"lax"}get(){const e=document.cookie.split(";");for(const t of e){const[e,s]=t.trim().split("=");if(e===this.cookieName)try{return JSON.parse(decodeURIComponent(s||""))}catch{return this.remove(),null}}return null}set(e){const t=new Date;t.setTime(t.getTime()+24*this.expirationDays*60*60*1e3);const s=encodeURIComponent(JSON.stringify(e)),o=`${this.cookieName}=${s}; expires=${t.toUTCString()}; path=/; ${this.secure?"secure; ":""}SameSite=${this.sameSite}`;document.cookie=o}remove(){document.cookie=`${this.cookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; ${this.secure?"secure; ":""}SameSite=${this.sameSite}`}},exports.DEFAULT_SESSION_KEY=r,exports.LocalStorage=i,exports.MemoryStorage=n,exports.SessionStorage=class{storage;subscribers=new Set;constructor(e){this.storage=e}get(){return this.storage.get()}set(e){const s=t(e.accessToken),o={...e,decodedToken:s};this.storage.set(o),this.notifySubscribers(o)}remove(){this.storage.remove(),this.notifySubscribers(null)}onChange(e){return this.subscribers.add(e),()=>{this.subscribers.delete(e)}}notifySubscribers(e){for(const s of this.subscribers)try{s(e)}catch(t){console.error("Error notifying subscriber:",t)}}},exports.detectStorage=()=>"undefined"!=typeof window?new i:new n;
2
2
  //# sourceMappingURL=session.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"session.cjs","sources":["../../src/session/session.ts","../../src/session/storageBackend.ts","../../src/session/storage.ts"],"sourcesContent":["import type { Session as AuthSession } from '../auth';\n\n/**\n * Decoded JWT token payload with processed timestamps and Hasura claims\n */\nexport interface DecodedToken {\n /** Token expiration time as Date object */\n exp?: number;\n /** Token issued at time as Date object */\n iat?: number;\n /** Token issuer */\n iss?: string;\n /** Token subject (user ID) */\n sub?: string;\n /** Hasura JWT claims with PostgreSQL arrays converted to JavaScript arrays */\n 'https://hasura.io/jwt/claims'?: Record<string, unknown>;\n /** Any other JWT claims */\n [key: string]: unknown;\n}\n\nexport interface Session extends AuthSession {\n /** Decoded JWT token payload with processed timestamps and Hasura claims */\n decodedToken: DecodedToken;\n}\n\nexport const decodeUserSession = (accessToken: string): DecodedToken => {\n const s = accessToken.split('.');\n if (s.length !== 3 || !s[1]) {\n throw new Error('Invalid access token format');\n }\n\n const decodedToken = JSON.parse(\n typeof atob !== 'undefined'\n ? atob(s[1])\n : Buffer.from(s[1], 'base64').toString('utf-8'),\n ) as Record<string, unknown>;\n\n // Convert iat and exp to Date objects\n const iat =\n typeof decodedToken['iat'] === 'number'\n ? decodedToken['iat'] * 1000 // Convert seconds to milliseconds\n : undefined;\n const exp =\n typeof decodedToken['exp'] === 'number'\n ? decodedToken['exp'] * 1000 // Convert seconds to milliseconds\n : undefined;\n\n // Process Hasura claims - dynamically convert PostgreSQL array notation to arrays\n const hasuraClaims = decodedToken['https://hasura.io/jwt/claims'] as\n | Record<string, unknown>\n | undefined;\n const processedClaims = hasuraClaims\n ? Object.entries(hasuraClaims).reduce(\n (acc, [key, value]) => {\n if (typeof value === 'string' && isPostgresArray(value)) {\n acc[key] = parsePostgresArray(value);\n } else {\n acc[key] = value;\n }\n return acc;\n },\n {} as Record<string, unknown>,\n )\n : undefined;\n\n return {\n ...decodedToken,\n iat,\n exp,\n 'https://hasura.io/jwt/claims': processedClaims,\n };\n};\n\nconst isPostgresArray = (value: string): boolean => {\n return value.startsWith('{') && value.endsWith('}');\n};\n\nconst parsePostgresArray = (value: string): string[] => {\n if (!value || value === '{}') return [];\n // Remove curly braces and split by comma, handling quoted values\n return value\n .slice(1, -1)\n .split(',')\n .map((item) => item.trim().replace(/^\"(.*)\"$/, '$1'));\n};\n","/**\n * Storage implementations for session persistence in different environments.\n *\n * This module provides different storage adapters for persisting authentication sessions\n * across page reloads and browser sessions.\n */\n\nimport type { Session } from './session';\n\n/**\n * Session storage interface for session persistence.\n * This interface can be implemented to provide custom storage solutions.\n */\nexport interface SessionStorageBackend {\n /**\n * Get the current session from storage\n * @returns The stored session or null if not found\n */\n get(): Session | null;\n\n /**\n * Set the session in storage\n * @param value - The session to store\n */\n set(value: Session): void;\n\n /**\n * Remove the session from storage\n */\n remove(): void;\n}\n\n/**\n * Default storage key used for storing the Nhost session\n */\nexport const DEFAULT_SESSION_KEY = 'nhostSession';\n\n/**\n * Browser localStorage implementation of StorageInterface.\n * Persists the session across page reloads and browser restarts.\n */\nexport class LocalStorage implements SessionStorageBackend {\n private readonly storageKey: string;\n\n /**\n * Creates a new LocalStorage instance\n * @param options - Configuration options\n * @param options.storageKey - The key to use in localStorage (defaults to \"nhostSession\")\n */\n constructor(options?: { storageKey?: string }) {\n this.storageKey = options?.storageKey || DEFAULT_SESSION_KEY;\n }\n\n /**\n * Gets the session from localStorage\n * @returns The stored session or null if not found\n */\n get(): Session | null {\n try {\n const value = window.localStorage.getItem(this.storageKey);\n return value ? (JSON.parse(value) as Session) : null;\n } catch {\n this.remove();\n return null;\n }\n }\n\n /**\n * Sets the session in localStorage\n * @param value - The session to store\n */\n set(value: Session): void {\n window.localStorage.setItem(this.storageKey, JSON.stringify(value));\n }\n\n /**\n * Removes the session from localStorage\n */\n remove(): void {\n window.localStorage.removeItem(this.storageKey);\n }\n}\n\n/**\n * In-memory storage implementation for non-browser environments or when\n * persistent storage is not available or desirable.\n */\nexport class MemoryStorage implements SessionStorageBackend {\n private session: Session | null = null;\n\n /**\n * Gets the session from memory\n * @returns The stored session or null if not set\n */\n get(): Session | null {\n return this.session;\n }\n\n /**\n * Sets the session in memory\n * @param value - The session to store\n */\n set(value: Session): void {\n this.session = value;\n }\n\n /**\n * Clears the session from memory\n */\n remove(): void {\n this.session = null;\n }\n}\n\n/**\n * Cookie-based storage implementation.\n * This storage uses web browser cookies to store the session so it's not\n * available in server-side environments. It is useful though for synchronizing\n * sessions between client and server environments.\n */\nexport class CookieStorage implements SessionStorageBackend {\n private readonly cookieName: string;\n private readonly expirationDays: number;\n private readonly secure: boolean;\n private readonly sameSite: 'strict' | 'lax' | 'none';\n\n /**\n * Creates a new CookieStorage instance\n * @param options - Configuration options\n * @param options.cookieName - Name of the cookie to use (defaults to \"nhostSession\")\n * @param options.expirationDays - Number of days until the cookie expires (defaults to 30)\n * @param options.secure - Whether to set the Secure flag on the cookie (defaults to true)\n * @param options.sameSite - SameSite policy for the cookie (defaults to \"lax\")\n */\n constructor(options?: {\n cookieName?: string;\n expirationDays?: number;\n secure?: boolean;\n sameSite?: 'strict' | 'lax' | 'none';\n }) {\n this.cookieName = options?.cookieName || DEFAULT_SESSION_KEY;\n this.expirationDays = options?.expirationDays ?? 30;\n this.secure = options?.secure ?? true;\n this.sameSite = options?.sameSite || 'lax';\n }\n\n /**\n * Gets the session from cookies\n * @returns The stored session or null if not found\n */\n get(): Session | null {\n const cookies = document.cookie.split(';');\n for (const cookie of cookies) {\n const [name, value] = cookie.trim().split('=');\n if (name === this.cookieName) {\n try {\n return JSON.parse(decodeURIComponent(value || '')) as Session;\n } catch {\n this.remove();\n return null;\n }\n }\n }\n return null;\n }\n\n /**\n * Sets the session in a cookie\n * @param value - The session to store\n */\n set(value: Session): void {\n const expires = new Date();\n expires.setTime(\n expires.getTime() + this.expirationDays * 24 * 60 * 60 * 1000,\n );\n\n const cookieValue = encodeURIComponent(JSON.stringify(value));\n const cookieString = `${this.cookieName}=${cookieValue}; expires=${expires.toUTCString()}; path=/; ${this.secure ? 'secure; ' : ''}SameSite=${this.sameSite}`;\n\n // biome-ignore lint/suspicious/noDocumentCookie: this is unnecessary\n document.cookie = cookieString;\n }\n\n /**\n * Removes the session cookie\n */\n remove(): void {\n // biome-ignore lint/suspicious/noDocumentCookie: this is unnecessary\n document.cookie = `${this.cookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; ${this.secure ? 'secure; ' : ''}SameSite=${this.sameSite}`;\n }\n}\n","/**\n * Storage implementations for session persistence in different environments.\n *\n * This module provides different storage adapters for persisting authentication sessions\n * across page reloads and browser sessions.\n */\n\nimport type { Session as AuthSession } from '../auth';\nimport { decodeUserSession, type Session } from './session';\nimport {\n LocalStorage,\n MemoryStorage,\n type SessionStorageBackend,\n} from './storageBackend';\n\n/**\n * Callback function type for session change subscriptions\n */\nexport type SessionChangeCallback = (session: Session | null) => void;\n\n/**\n * A wrapper around any SessionStorageInterface implementation that adds\n * the ability to subscribe to session changes.\n */\nexport class SessionStorage {\n private readonly storage: SessionStorageBackend;\n private subscribers = new Set<SessionChangeCallback>();\n\n /**\n * Creates a new SessionStorage instance\n * @param storage - The underlying storage implementation to use\n */\n constructor(storage: SessionStorageBackend) {\n this.storage = storage;\n }\n\n /**\n * Gets the session from the underlying storage\n * @returns The stored session or null if not found\n */\n get(): Session | null {\n return this.storage.get();\n }\n\n /**\n * Sets the session in the underlying storage and notifies subscribers\n * @param value - The session to store\n */\n set(value: AuthSession): void {\n const decodedToken = decodeUserSession(value.accessToken);\n const decodedSession = {\n ...value,\n decodedToken: decodedToken,\n };\n\n this.storage.set(decodedSession);\n this.notifySubscribers(decodedSession);\n }\n\n /**\n * Removes the session from the underlying storage and notifies subscribers\n */\n remove(): void {\n this.storage.remove();\n this.notifySubscribers(null);\n }\n\n /**\n * Subscribe to session changes\n * @param callback - Function that will be called when the session changes\n * @returns An unsubscribe function to remove this subscription\n */\n onChange(callback: SessionChangeCallback) {\n this.subscribers.add(callback);\n\n return () => {\n this.subscribers.delete(callback);\n };\n }\n\n /**\n * Notify all subscribers of a session change\n * @param session - The new session value or null if removed\n */\n private notifySubscribers(session: Session | null): void {\n for (const subscriber of this.subscribers) {\n try {\n subscriber(session);\n } catch (error) {\n console.error('Error notifying subscriber:', error);\n }\n }\n }\n}\n\n/**\n * Detects the best available storage implementation for the current environment.\n *\n * The detection process follows this order:\n * 1. Try to use localStorage if we're in a browser environment\n * 2. Fall back to in-memory storage if localStorage isn't available\n *\n * @returns The best available storage implementation as a SessionStorageBackend\n */\nexport const detectStorage = (): SessionStorageBackend => {\n if (typeof window !== 'undefined') {\n return new LocalStorage();\n }\n return new MemoryStorage();\n};\n"],"names":["isPostgresArray","value","startsWith","endsWith","parsePostgresArray","slice","split","map","item","trim","replace","DEFAULT_SESSION_KEY","LocalStorage","storageKey","constructor","options","this","get","window","localStorage","getItem","JSON","parse","remove","set","setItem","stringify","removeItem","MemoryStorage","session","cookieName","expirationDays","secure","sameSite","cookies","document","cookie","name","decodeURIComponent","expires","Date","setTime","getTime","cookieValue","encodeURIComponent","cookieString","toUTCString","storage","subscribers","Set","decodedToken","accessToken","s","length","Error","atob","Buffer","from","toString","iat","exp","hasuraClaims","processedClaims","Object","entries","reduce","acc","key","decodeUserSession","decodedSession","notifySubscribers","onChange","callback","add","delete","subscriber","error","console"],"mappings":"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"}
1
+ {"version":3,"file":"session.cjs","sources":["../../src/session/session.ts","../../src/session/storageBackend.ts","../../src/session/storage.ts"],"sourcesContent":["import type { Session as AuthSession } from '../auth';\n\n/**\n * Decoded JWT token payload with processed timestamps and Hasura claims\n */\nexport interface DecodedToken {\n /** Token expiration time as Date object */\n exp?: number;\n /** Token issued at time as Date object */\n iat?: number;\n /** Token issuer */\n iss?: string;\n /** Token subject (user ID) */\n sub?: string;\n /** Hasura JWT claims with PostgreSQL arrays converted to JavaScript arrays */\n 'https://hasura.io/jwt/claims'?: Record<string, unknown>;\n /** Any other JWT claims */\n [key: string]: unknown;\n}\n\nexport interface Session extends AuthSession {\n /** Decoded JWT token payload with processed timestamps and Hasura claims */\n decodedToken: DecodedToken;\n}\n\n/**\n * Decodes a base64url-encoded string (RFC 4648 Section 5) to a UTF-8 string.\n *\n * JWTs use base64url encoding, which differs from standard base64 by using\n * `-` and `_` instead of `+` and `/`, and omitting padding. The browser's\n * native `atob()` does not support base64url, so we must handle the conversion.\n */\nconst decodeBase64Url = (input: string): string => {\n // Convert base64url to standard base64\n let base64 = input.replace(/-/g, '+').replace(/_/g, '/');\n const pad = base64.length % 4;\n if (pad) {\n base64 += '='.repeat(4 - pad);\n }\n\n // Use TextDecoder for proper UTF-8 support (atob alone mangles multi-byte characters)\n const binaryString = atob(base64);\n const bytes = Uint8Array.from(binaryString, (c) => c.charCodeAt(0));\n return new TextDecoder().decode(bytes);\n};\n\nexport const decodeUserSession = (accessToken: string): DecodedToken => {\n const s = accessToken.split('.');\n if (s.length !== 3 || !s[1]) {\n throw new Error('Invalid access token format');\n }\n\n const decodedToken = JSON.parse(decodeBase64Url(s[1])) as Record<\n string,\n unknown\n >;\n\n // Convert iat and exp to Date objects\n const iat =\n typeof decodedToken['iat'] === 'number'\n ? decodedToken['iat'] * 1000 // Convert seconds to milliseconds\n : undefined;\n const exp =\n typeof decodedToken['exp'] === 'number'\n ? decodedToken['exp'] * 1000 // Convert seconds to milliseconds\n : undefined;\n\n // Process Hasura claims - dynamically convert PostgreSQL array notation to arrays\n const hasuraClaims = decodedToken['https://hasura.io/jwt/claims'] as\n | Record<string, unknown>\n | undefined;\n const processedClaims = hasuraClaims\n ? Object.entries(hasuraClaims).reduce(\n (acc, [key, value]) => {\n if (typeof value === 'string' && isPostgresArray(value)) {\n acc[key] = parsePostgresArray(value);\n } else {\n acc[key] = value;\n }\n return acc;\n },\n {} as Record<string, unknown>,\n )\n : undefined;\n\n return {\n ...decodedToken,\n iat,\n exp,\n 'https://hasura.io/jwt/claims': processedClaims,\n };\n};\n\nconst isPostgresArray = (value: string): boolean => {\n return value.startsWith('{') && value.endsWith('}');\n};\n\nconst parsePostgresArray = (value: string): string[] => {\n if (!value || value === '{}') return [];\n // Remove curly braces and split by comma, handling quoted values\n return value\n .slice(1, -1)\n .split(',')\n .map((item) => item.trim().replace(/^\"(.*)\"$/, '$1'));\n};\n","/**\n * Storage implementations for session persistence in different environments.\n *\n * This module provides different storage adapters for persisting authentication sessions\n * across page reloads and browser sessions.\n */\n\nimport type { Session } from './session';\n\n/**\n * Session storage interface for session persistence.\n * This interface can be implemented to provide custom storage solutions.\n */\nexport interface SessionStorageBackend {\n /**\n * Get the current session from storage\n * @returns The stored session or null if not found\n */\n get(): Session | null;\n\n /**\n * Set the session in storage\n * @param value - The session to store\n */\n set(value: Session): void;\n\n /**\n * Remove the session from storage\n */\n remove(): void;\n}\n\n/**\n * Default storage key used for storing the Nhost session\n */\nexport const DEFAULT_SESSION_KEY = 'nhostSession';\n\n/**\n * Browser localStorage implementation of StorageInterface.\n * Persists the session across page reloads and browser restarts.\n */\nexport class LocalStorage implements SessionStorageBackend {\n private readonly storageKey: string;\n\n /**\n * Creates a new LocalStorage instance\n * @param options - Configuration options\n * @param options.storageKey - The key to use in localStorage (defaults to \"nhostSession\")\n */\n constructor(options?: { storageKey?: string }) {\n this.storageKey = options?.storageKey || DEFAULT_SESSION_KEY;\n }\n\n /**\n * Gets the session from localStorage\n * @returns The stored session or null if not found\n */\n get(): Session | null {\n try {\n const value = window.localStorage.getItem(this.storageKey);\n return value ? (JSON.parse(value) as Session) : null;\n } catch {\n this.remove();\n return null;\n }\n }\n\n /**\n * Sets the session in localStorage\n * @param value - The session to store\n */\n set(value: Session): void {\n window.localStorage.setItem(this.storageKey, JSON.stringify(value));\n }\n\n /**\n * Removes the session from localStorage\n */\n remove(): void {\n window.localStorage.removeItem(this.storageKey);\n }\n}\n\n/**\n * In-memory storage implementation for non-browser environments or when\n * persistent storage is not available or desirable.\n */\nexport class MemoryStorage implements SessionStorageBackend {\n private session: Session | null = null;\n\n /**\n * Gets the session from memory\n * @returns The stored session or null if not set\n */\n get(): Session | null {\n return this.session;\n }\n\n /**\n * Sets the session in memory\n * @param value - The session to store\n */\n set(value: Session): void {\n this.session = value;\n }\n\n /**\n * Clears the session from memory\n */\n remove(): void {\n this.session = null;\n }\n}\n\n/**\n * Cookie-based storage implementation.\n * This storage uses web browser cookies to store the session so it's not\n * available in server-side environments. It is useful though for synchronizing\n * sessions between client and server environments.\n */\nexport class CookieStorage implements SessionStorageBackend {\n private readonly cookieName: string;\n private readonly expirationDays: number;\n private readonly secure: boolean;\n private readonly sameSite: 'strict' | 'lax' | 'none';\n\n /**\n * Creates a new CookieStorage instance\n * @param options - Configuration options\n * @param options.cookieName - Name of the cookie to use (defaults to \"nhostSession\")\n * @param options.expirationDays - Number of days until the cookie expires (defaults to 30)\n * @param options.secure - Whether to set the Secure flag on the cookie (defaults to true)\n * @param options.sameSite - SameSite policy for the cookie (defaults to \"lax\")\n */\n constructor(options?: {\n cookieName?: string;\n expirationDays?: number;\n secure?: boolean;\n sameSite?: 'strict' | 'lax' | 'none';\n }) {\n this.cookieName = options?.cookieName || DEFAULT_SESSION_KEY;\n this.expirationDays = options?.expirationDays ?? 30;\n this.secure = options?.secure ?? true;\n this.sameSite = options?.sameSite || 'lax';\n }\n\n /**\n * Gets the session from cookies\n * @returns The stored session or null if not found\n */\n get(): Session | null {\n const cookies = document.cookie.split(';');\n for (const cookie of cookies) {\n const [name, value] = cookie.trim().split('=');\n if (name === this.cookieName) {\n try {\n return JSON.parse(decodeURIComponent(value || '')) as Session;\n } catch {\n this.remove();\n return null;\n }\n }\n }\n return null;\n }\n\n /**\n * Sets the session in a cookie\n * @param value - The session to store\n */\n set(value: Session): void {\n const expires = new Date();\n expires.setTime(\n expires.getTime() + this.expirationDays * 24 * 60 * 60 * 1000,\n );\n\n const cookieValue = encodeURIComponent(JSON.stringify(value));\n const cookieString = `${this.cookieName}=${cookieValue}; expires=${expires.toUTCString()}; path=/; ${this.secure ? 'secure; ' : ''}SameSite=${this.sameSite}`;\n\n // biome-ignore lint/suspicious/noDocumentCookie: this is unnecessary\n document.cookie = cookieString;\n }\n\n /**\n * Removes the session cookie\n */\n remove(): void {\n // biome-ignore lint/suspicious/noDocumentCookie: this is unnecessary\n document.cookie = `${this.cookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; ${this.secure ? 'secure; ' : ''}SameSite=${this.sameSite}`;\n }\n}\n","/**\n * Storage implementations for session persistence in different environments.\n *\n * This module provides different storage adapters for persisting authentication sessions\n * across page reloads and browser sessions.\n */\n\nimport type { Session as AuthSession } from '../auth';\nimport { decodeUserSession, type Session } from './session';\nimport {\n LocalStorage,\n MemoryStorage,\n type SessionStorageBackend,\n} from './storageBackend';\n\n/**\n * Callback function type for session change subscriptions\n */\nexport type SessionChangeCallback = (session: Session | null) => void;\n\n/**\n * A wrapper around any SessionStorageInterface implementation that adds\n * the ability to subscribe to session changes.\n */\nexport class SessionStorage {\n private readonly storage: SessionStorageBackend;\n private subscribers = new Set<SessionChangeCallback>();\n\n /**\n * Creates a new SessionStorage instance\n * @param storage - The underlying storage implementation to use\n */\n constructor(storage: SessionStorageBackend) {\n this.storage = storage;\n }\n\n /**\n * Gets the session from the underlying storage\n * @returns The stored session or null if not found\n */\n get(): Session | null {\n return this.storage.get();\n }\n\n /**\n * Sets the session in the underlying storage and notifies subscribers\n * @param value - The session to store\n */\n set(value: AuthSession): void {\n const decodedToken = decodeUserSession(value.accessToken);\n const decodedSession = {\n ...value,\n decodedToken: decodedToken,\n };\n\n this.storage.set(decodedSession);\n this.notifySubscribers(decodedSession);\n }\n\n /**\n * Removes the session from the underlying storage and notifies subscribers\n */\n remove(): void {\n this.storage.remove();\n this.notifySubscribers(null);\n }\n\n /**\n * Subscribe to session changes\n * @param callback - Function that will be called when the session changes\n * @returns An unsubscribe function to remove this subscription\n */\n onChange(callback: SessionChangeCallback) {\n this.subscribers.add(callback);\n\n return () => {\n this.subscribers.delete(callback);\n };\n }\n\n /**\n * Notify all subscribers of a session change\n * @param session - The new session value or null if removed\n */\n private notifySubscribers(session: Session | null): void {\n for (const subscriber of this.subscribers) {\n try {\n subscriber(session);\n } catch (error) {\n console.error('Error notifying subscriber:', error);\n }\n }\n }\n}\n\n/**\n * Detects the best available storage implementation for the current environment.\n *\n * The detection process follows this order:\n * 1. Try to use localStorage if we're in a browser environment\n * 2. Fall back to in-memory storage if localStorage isn't available\n *\n * @returns The best available storage implementation as a SessionStorageBackend\n */\nexport const detectStorage = (): SessionStorageBackend => {\n if (typeof window !== 'undefined') {\n return new LocalStorage();\n }\n return new MemoryStorage();\n};\n"],"names":["decodeUserSession","accessToken","s","split","length","Error","decodedToken","JSON","parse","input","base64","replace","pad","repeat","binaryString","atob","bytes","Uint8Array","from","c","charCodeAt","TextDecoder","decode","decodeBase64Url","iat","exp","hasuraClaims","processedClaims","Object","entries","reduce","acc","key","value","isPostgresArray","parsePostgresArray","startsWith","endsWith","slice","map","item","trim","DEFAULT_SESSION_KEY","LocalStorage","storageKey","constructor","options","this","get","window","localStorage","getItem","remove","set","setItem","stringify","removeItem","MemoryStorage","session","cookieName","expirationDays","secure","sameSite","cookies","document","cookie","name","decodeURIComponent","expires","Date","setTime","getTime","cookieValue","encodeURIComponent","cookieString","toUTCString","storage","subscribers","Set","decodedSession","notifySubscribers","onChange","callback","add","delete","subscriber","error","console"],"mappings":"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"}
@@ -1,12 +1,20 @@
1
1
  import { r } from "../refreshSession-WwGlzgtM.js";
2
+ const decodeBase64Url = (input) => {
3
+ let base64 = input.replace(/-/g, "+").replace(/_/g, "/");
4
+ const pad = base64.length % 4;
5
+ if (pad) {
6
+ base64 += "=".repeat(4 - pad);
7
+ }
8
+ const binaryString = atob(base64);
9
+ const bytes = Uint8Array.from(binaryString, (c) => c.charCodeAt(0));
10
+ return new TextDecoder().decode(bytes);
11
+ };
2
12
  const decodeUserSession = (accessToken) => {
3
13
  const s = accessToken.split(".");
4
14
  if (s.length !== 3 || !s[1]) {
5
15
  throw new Error("Invalid access token format");
6
16
  }
7
- const decodedToken = JSON.parse(
8
- typeof atob !== "undefined" ? atob(s[1]) : Buffer.from(s[1], "base64").toString("utf-8")
9
- );
17
+ const decodedToken = JSON.parse(decodeBase64Url(s[1]));
10
18
  const iat = typeof decodedToken["iat"] === "number" ? decodedToken["iat"] * 1e3 : void 0;
11
19
  const exp = typeof decodedToken["exp"] === "number" ? decodedToken["exp"] * 1e3 : void 0;
12
20
  const hasuraClaims = decodedToken["https://hasura.io/jwt/claims"];
@@ -1 +1 @@
1
- {"version":3,"file":"session.js","sources":["../../src/session/session.ts","../../src/session/storageBackend.ts","../../src/session/storage.ts"],"sourcesContent":["import type { Session as AuthSession } from '../auth';\n\n/**\n * Decoded JWT token payload with processed timestamps and Hasura claims\n */\nexport interface DecodedToken {\n /** Token expiration time as Date object */\n exp?: number;\n /** Token issued at time as Date object */\n iat?: number;\n /** Token issuer */\n iss?: string;\n /** Token subject (user ID) */\n sub?: string;\n /** Hasura JWT claims with PostgreSQL arrays converted to JavaScript arrays */\n 'https://hasura.io/jwt/claims'?: Record<string, unknown>;\n /** Any other JWT claims */\n [key: string]: unknown;\n}\n\nexport interface Session extends AuthSession {\n /** Decoded JWT token payload with processed timestamps and Hasura claims */\n decodedToken: DecodedToken;\n}\n\nexport const decodeUserSession = (accessToken: string): DecodedToken => {\n const s = accessToken.split('.');\n if (s.length !== 3 || !s[1]) {\n throw new Error('Invalid access token format');\n }\n\n const decodedToken = JSON.parse(\n typeof atob !== 'undefined'\n ? atob(s[1])\n : Buffer.from(s[1], 'base64').toString('utf-8'),\n ) as Record<string, unknown>;\n\n // Convert iat and exp to Date objects\n const iat =\n typeof decodedToken['iat'] === 'number'\n ? decodedToken['iat'] * 1000 // Convert seconds to milliseconds\n : undefined;\n const exp =\n typeof decodedToken['exp'] === 'number'\n ? decodedToken['exp'] * 1000 // Convert seconds to milliseconds\n : undefined;\n\n // Process Hasura claims - dynamically convert PostgreSQL array notation to arrays\n const hasuraClaims = decodedToken['https://hasura.io/jwt/claims'] as\n | Record<string, unknown>\n | undefined;\n const processedClaims = hasuraClaims\n ? Object.entries(hasuraClaims).reduce(\n (acc, [key, value]) => {\n if (typeof value === 'string' && isPostgresArray(value)) {\n acc[key] = parsePostgresArray(value);\n } else {\n acc[key] = value;\n }\n return acc;\n },\n {} as Record<string, unknown>,\n )\n : undefined;\n\n return {\n ...decodedToken,\n iat,\n exp,\n 'https://hasura.io/jwt/claims': processedClaims,\n };\n};\n\nconst isPostgresArray = (value: string): boolean => {\n return value.startsWith('{') && value.endsWith('}');\n};\n\nconst parsePostgresArray = (value: string): string[] => {\n if (!value || value === '{}') return [];\n // Remove curly braces and split by comma, handling quoted values\n return value\n .slice(1, -1)\n .split(',')\n .map((item) => item.trim().replace(/^\"(.*)\"$/, '$1'));\n};\n","/**\n * Storage implementations for session persistence in different environments.\n *\n * This module provides different storage adapters for persisting authentication sessions\n * across page reloads and browser sessions.\n */\n\nimport type { Session } from './session';\n\n/**\n * Session storage interface for session persistence.\n * This interface can be implemented to provide custom storage solutions.\n */\nexport interface SessionStorageBackend {\n /**\n * Get the current session from storage\n * @returns The stored session or null if not found\n */\n get(): Session | null;\n\n /**\n * Set the session in storage\n * @param value - The session to store\n */\n set(value: Session): void;\n\n /**\n * Remove the session from storage\n */\n remove(): void;\n}\n\n/**\n * Default storage key used for storing the Nhost session\n */\nexport const DEFAULT_SESSION_KEY = 'nhostSession';\n\n/**\n * Browser localStorage implementation of StorageInterface.\n * Persists the session across page reloads and browser restarts.\n */\nexport class LocalStorage implements SessionStorageBackend {\n private readonly storageKey: string;\n\n /**\n * Creates a new LocalStorage instance\n * @param options - Configuration options\n * @param options.storageKey - The key to use in localStorage (defaults to \"nhostSession\")\n */\n constructor(options?: { storageKey?: string }) {\n this.storageKey = options?.storageKey || DEFAULT_SESSION_KEY;\n }\n\n /**\n * Gets the session from localStorage\n * @returns The stored session or null if not found\n */\n get(): Session | null {\n try {\n const value = window.localStorage.getItem(this.storageKey);\n return value ? (JSON.parse(value) as Session) : null;\n } catch {\n this.remove();\n return null;\n }\n }\n\n /**\n * Sets the session in localStorage\n * @param value - The session to store\n */\n set(value: Session): void {\n window.localStorage.setItem(this.storageKey, JSON.stringify(value));\n }\n\n /**\n * Removes the session from localStorage\n */\n remove(): void {\n window.localStorage.removeItem(this.storageKey);\n }\n}\n\n/**\n * In-memory storage implementation for non-browser environments or when\n * persistent storage is not available or desirable.\n */\nexport class MemoryStorage implements SessionStorageBackend {\n private session: Session | null = null;\n\n /**\n * Gets the session from memory\n * @returns The stored session or null if not set\n */\n get(): Session | null {\n return this.session;\n }\n\n /**\n * Sets the session in memory\n * @param value - The session to store\n */\n set(value: Session): void {\n this.session = value;\n }\n\n /**\n * Clears the session from memory\n */\n remove(): void {\n this.session = null;\n }\n}\n\n/**\n * Cookie-based storage implementation.\n * This storage uses web browser cookies to store the session so it's not\n * available in server-side environments. It is useful though for synchronizing\n * sessions between client and server environments.\n */\nexport class CookieStorage implements SessionStorageBackend {\n private readonly cookieName: string;\n private readonly expirationDays: number;\n private readonly secure: boolean;\n private readonly sameSite: 'strict' | 'lax' | 'none';\n\n /**\n * Creates a new CookieStorage instance\n * @param options - Configuration options\n * @param options.cookieName - Name of the cookie to use (defaults to \"nhostSession\")\n * @param options.expirationDays - Number of days until the cookie expires (defaults to 30)\n * @param options.secure - Whether to set the Secure flag on the cookie (defaults to true)\n * @param options.sameSite - SameSite policy for the cookie (defaults to \"lax\")\n */\n constructor(options?: {\n cookieName?: string;\n expirationDays?: number;\n secure?: boolean;\n sameSite?: 'strict' | 'lax' | 'none';\n }) {\n this.cookieName = options?.cookieName || DEFAULT_SESSION_KEY;\n this.expirationDays = options?.expirationDays ?? 30;\n this.secure = options?.secure ?? true;\n this.sameSite = options?.sameSite || 'lax';\n }\n\n /**\n * Gets the session from cookies\n * @returns The stored session or null if not found\n */\n get(): Session | null {\n const cookies = document.cookie.split(';');\n for (const cookie of cookies) {\n const [name, value] = cookie.trim().split('=');\n if (name === this.cookieName) {\n try {\n return JSON.parse(decodeURIComponent(value || '')) as Session;\n } catch {\n this.remove();\n return null;\n }\n }\n }\n return null;\n }\n\n /**\n * Sets the session in a cookie\n * @param value - The session to store\n */\n set(value: Session): void {\n const expires = new Date();\n expires.setTime(\n expires.getTime() + this.expirationDays * 24 * 60 * 60 * 1000,\n );\n\n const cookieValue = encodeURIComponent(JSON.stringify(value));\n const cookieString = `${this.cookieName}=${cookieValue}; expires=${expires.toUTCString()}; path=/; ${this.secure ? 'secure; ' : ''}SameSite=${this.sameSite}`;\n\n // biome-ignore lint/suspicious/noDocumentCookie: this is unnecessary\n document.cookie = cookieString;\n }\n\n /**\n * Removes the session cookie\n */\n remove(): void {\n // biome-ignore lint/suspicious/noDocumentCookie: this is unnecessary\n document.cookie = `${this.cookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; ${this.secure ? 'secure; ' : ''}SameSite=${this.sameSite}`;\n }\n}\n","/**\n * Storage implementations for session persistence in different environments.\n *\n * This module provides different storage adapters for persisting authentication sessions\n * across page reloads and browser sessions.\n */\n\nimport type { Session as AuthSession } from '../auth';\nimport { decodeUserSession, type Session } from './session';\nimport {\n LocalStorage,\n MemoryStorage,\n type SessionStorageBackend,\n} from './storageBackend';\n\n/**\n * Callback function type for session change subscriptions\n */\nexport type SessionChangeCallback = (session: Session | null) => void;\n\n/**\n * A wrapper around any SessionStorageInterface implementation that adds\n * the ability to subscribe to session changes.\n */\nexport class SessionStorage {\n private readonly storage: SessionStorageBackend;\n private subscribers = new Set<SessionChangeCallback>();\n\n /**\n * Creates a new SessionStorage instance\n * @param storage - The underlying storage implementation to use\n */\n constructor(storage: SessionStorageBackend) {\n this.storage = storage;\n }\n\n /**\n * Gets the session from the underlying storage\n * @returns The stored session or null if not found\n */\n get(): Session | null {\n return this.storage.get();\n }\n\n /**\n * Sets the session in the underlying storage and notifies subscribers\n * @param value - The session to store\n */\n set(value: AuthSession): void {\n const decodedToken = decodeUserSession(value.accessToken);\n const decodedSession = {\n ...value,\n decodedToken: decodedToken,\n };\n\n this.storage.set(decodedSession);\n this.notifySubscribers(decodedSession);\n }\n\n /**\n * Removes the session from the underlying storage and notifies subscribers\n */\n remove(): void {\n this.storage.remove();\n this.notifySubscribers(null);\n }\n\n /**\n * Subscribe to session changes\n * @param callback - Function that will be called when the session changes\n * @returns An unsubscribe function to remove this subscription\n */\n onChange(callback: SessionChangeCallback) {\n this.subscribers.add(callback);\n\n return () => {\n this.subscribers.delete(callback);\n };\n }\n\n /**\n * Notify all subscribers of a session change\n * @param session - The new session value or null if removed\n */\n private notifySubscribers(session: Session | null): void {\n for (const subscriber of this.subscribers) {\n try {\n subscriber(session);\n } catch (error) {\n console.error('Error notifying subscriber:', error);\n }\n }\n }\n}\n\n/**\n * Detects the best available storage implementation for the current environment.\n *\n * The detection process follows this order:\n * 1. Try to use localStorage if we're in a browser environment\n * 2. Fall back to in-memory storage if localStorage isn't available\n *\n * @returns The best available storage implementation as a SessionStorageBackend\n */\nexport const detectStorage = (): SessionStorageBackend => {\n if (typeof window !== 'undefined') {\n return new LocalStorage();\n }\n return new MemoryStorage();\n};\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"session.js","sources":["../../src/session/session.ts","../../src/session/storageBackend.ts","../../src/session/storage.ts"],"sourcesContent":["import type { Session as AuthSession } from '../auth';\n\n/**\n * Decoded JWT token payload with processed timestamps and Hasura claims\n */\nexport interface DecodedToken {\n /** Token expiration time as Date object */\n exp?: number;\n /** Token issued at time as Date object */\n iat?: number;\n /** Token issuer */\n iss?: string;\n /** Token subject (user ID) */\n sub?: string;\n /** Hasura JWT claims with PostgreSQL arrays converted to JavaScript arrays */\n 'https://hasura.io/jwt/claims'?: Record<string, unknown>;\n /** Any other JWT claims */\n [key: string]: unknown;\n}\n\nexport interface Session extends AuthSession {\n /** Decoded JWT token payload with processed timestamps and Hasura claims */\n decodedToken: DecodedToken;\n}\n\n/**\n * Decodes a base64url-encoded string (RFC 4648 Section 5) to a UTF-8 string.\n *\n * JWTs use base64url encoding, which differs from standard base64 by using\n * `-` and `_` instead of `+` and `/`, and omitting padding. The browser's\n * native `atob()` does not support base64url, so we must handle the conversion.\n */\nconst decodeBase64Url = (input: string): string => {\n // Convert base64url to standard base64\n let base64 = input.replace(/-/g, '+').replace(/_/g, '/');\n const pad = base64.length % 4;\n if (pad) {\n base64 += '='.repeat(4 - pad);\n }\n\n // Use TextDecoder for proper UTF-8 support (atob alone mangles multi-byte characters)\n const binaryString = atob(base64);\n const bytes = Uint8Array.from(binaryString, (c) => c.charCodeAt(0));\n return new TextDecoder().decode(bytes);\n};\n\nexport const decodeUserSession = (accessToken: string): DecodedToken => {\n const s = accessToken.split('.');\n if (s.length !== 3 || !s[1]) {\n throw new Error('Invalid access token format');\n }\n\n const decodedToken = JSON.parse(decodeBase64Url(s[1])) as Record<\n string,\n unknown\n >;\n\n // Convert iat and exp to Date objects\n const iat =\n typeof decodedToken['iat'] === 'number'\n ? decodedToken['iat'] * 1000 // Convert seconds to milliseconds\n : undefined;\n const exp =\n typeof decodedToken['exp'] === 'number'\n ? decodedToken['exp'] * 1000 // Convert seconds to milliseconds\n : undefined;\n\n // Process Hasura claims - dynamically convert PostgreSQL array notation to arrays\n const hasuraClaims = decodedToken['https://hasura.io/jwt/claims'] as\n | Record<string, unknown>\n | undefined;\n const processedClaims = hasuraClaims\n ? Object.entries(hasuraClaims).reduce(\n (acc, [key, value]) => {\n if (typeof value === 'string' && isPostgresArray(value)) {\n acc[key] = parsePostgresArray(value);\n } else {\n acc[key] = value;\n }\n return acc;\n },\n {} as Record<string, unknown>,\n )\n : undefined;\n\n return {\n ...decodedToken,\n iat,\n exp,\n 'https://hasura.io/jwt/claims': processedClaims,\n };\n};\n\nconst isPostgresArray = (value: string): boolean => {\n return value.startsWith('{') && value.endsWith('}');\n};\n\nconst parsePostgresArray = (value: string): string[] => {\n if (!value || value === '{}') return [];\n // Remove curly braces and split by comma, handling quoted values\n return value\n .slice(1, -1)\n .split(',')\n .map((item) => item.trim().replace(/^\"(.*)\"$/, '$1'));\n};\n","/**\n * Storage implementations for session persistence in different environments.\n *\n * This module provides different storage adapters for persisting authentication sessions\n * across page reloads and browser sessions.\n */\n\nimport type { Session } from './session';\n\n/**\n * Session storage interface for session persistence.\n * This interface can be implemented to provide custom storage solutions.\n */\nexport interface SessionStorageBackend {\n /**\n * Get the current session from storage\n * @returns The stored session or null if not found\n */\n get(): Session | null;\n\n /**\n * Set the session in storage\n * @param value - The session to store\n */\n set(value: Session): void;\n\n /**\n * Remove the session from storage\n */\n remove(): void;\n}\n\n/**\n * Default storage key used for storing the Nhost session\n */\nexport const DEFAULT_SESSION_KEY = 'nhostSession';\n\n/**\n * Browser localStorage implementation of StorageInterface.\n * Persists the session across page reloads and browser restarts.\n */\nexport class LocalStorage implements SessionStorageBackend {\n private readonly storageKey: string;\n\n /**\n * Creates a new LocalStorage instance\n * @param options - Configuration options\n * @param options.storageKey - The key to use in localStorage (defaults to \"nhostSession\")\n */\n constructor(options?: { storageKey?: string }) {\n this.storageKey = options?.storageKey || DEFAULT_SESSION_KEY;\n }\n\n /**\n * Gets the session from localStorage\n * @returns The stored session or null if not found\n */\n get(): Session | null {\n try {\n const value = window.localStorage.getItem(this.storageKey);\n return value ? (JSON.parse(value) as Session) : null;\n } catch {\n this.remove();\n return null;\n }\n }\n\n /**\n * Sets the session in localStorage\n * @param value - The session to store\n */\n set(value: Session): void {\n window.localStorage.setItem(this.storageKey, JSON.stringify(value));\n }\n\n /**\n * Removes the session from localStorage\n */\n remove(): void {\n window.localStorage.removeItem(this.storageKey);\n }\n}\n\n/**\n * In-memory storage implementation for non-browser environments or when\n * persistent storage is not available or desirable.\n */\nexport class MemoryStorage implements SessionStorageBackend {\n private session: Session | null = null;\n\n /**\n * Gets the session from memory\n * @returns The stored session or null if not set\n */\n get(): Session | null {\n return this.session;\n }\n\n /**\n * Sets the session in memory\n * @param value - The session to store\n */\n set(value: Session): void {\n this.session = value;\n }\n\n /**\n * Clears the session from memory\n */\n remove(): void {\n this.session = null;\n }\n}\n\n/**\n * Cookie-based storage implementation.\n * This storage uses web browser cookies to store the session so it's not\n * available in server-side environments. It is useful though for synchronizing\n * sessions between client and server environments.\n */\nexport class CookieStorage implements SessionStorageBackend {\n private readonly cookieName: string;\n private readonly expirationDays: number;\n private readonly secure: boolean;\n private readonly sameSite: 'strict' | 'lax' | 'none';\n\n /**\n * Creates a new CookieStorage instance\n * @param options - Configuration options\n * @param options.cookieName - Name of the cookie to use (defaults to \"nhostSession\")\n * @param options.expirationDays - Number of days until the cookie expires (defaults to 30)\n * @param options.secure - Whether to set the Secure flag on the cookie (defaults to true)\n * @param options.sameSite - SameSite policy for the cookie (defaults to \"lax\")\n */\n constructor(options?: {\n cookieName?: string;\n expirationDays?: number;\n secure?: boolean;\n sameSite?: 'strict' | 'lax' | 'none';\n }) {\n this.cookieName = options?.cookieName || DEFAULT_SESSION_KEY;\n this.expirationDays = options?.expirationDays ?? 30;\n this.secure = options?.secure ?? true;\n this.sameSite = options?.sameSite || 'lax';\n }\n\n /**\n * Gets the session from cookies\n * @returns The stored session or null if not found\n */\n get(): Session | null {\n const cookies = document.cookie.split(';');\n for (const cookie of cookies) {\n const [name, value] = cookie.trim().split('=');\n if (name === this.cookieName) {\n try {\n return JSON.parse(decodeURIComponent(value || '')) as Session;\n } catch {\n this.remove();\n return null;\n }\n }\n }\n return null;\n }\n\n /**\n * Sets the session in a cookie\n * @param value - The session to store\n */\n set(value: Session): void {\n const expires = new Date();\n expires.setTime(\n expires.getTime() + this.expirationDays * 24 * 60 * 60 * 1000,\n );\n\n const cookieValue = encodeURIComponent(JSON.stringify(value));\n const cookieString = `${this.cookieName}=${cookieValue}; expires=${expires.toUTCString()}; path=/; ${this.secure ? 'secure; ' : ''}SameSite=${this.sameSite}`;\n\n // biome-ignore lint/suspicious/noDocumentCookie: this is unnecessary\n document.cookie = cookieString;\n }\n\n /**\n * Removes the session cookie\n */\n remove(): void {\n // biome-ignore lint/suspicious/noDocumentCookie: this is unnecessary\n document.cookie = `${this.cookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; ${this.secure ? 'secure; ' : ''}SameSite=${this.sameSite}`;\n }\n}\n","/**\n * Storage implementations for session persistence in different environments.\n *\n * This module provides different storage adapters for persisting authentication sessions\n * across page reloads and browser sessions.\n */\n\nimport type { Session as AuthSession } from '../auth';\nimport { decodeUserSession, type Session } from './session';\nimport {\n LocalStorage,\n MemoryStorage,\n type SessionStorageBackend,\n} from './storageBackend';\n\n/**\n * Callback function type for session change subscriptions\n */\nexport type SessionChangeCallback = (session: Session | null) => void;\n\n/**\n * A wrapper around any SessionStorageInterface implementation that adds\n * the ability to subscribe to session changes.\n */\nexport class SessionStorage {\n private readonly storage: SessionStorageBackend;\n private subscribers = new Set<SessionChangeCallback>();\n\n /**\n * Creates a new SessionStorage instance\n * @param storage - The underlying storage implementation to use\n */\n constructor(storage: SessionStorageBackend) {\n this.storage = storage;\n }\n\n /**\n * Gets the session from the underlying storage\n * @returns The stored session or null if not found\n */\n get(): Session | null {\n return this.storage.get();\n }\n\n /**\n * Sets the session in the underlying storage and notifies subscribers\n * @param value - The session to store\n */\n set(value: AuthSession): void {\n const decodedToken = decodeUserSession(value.accessToken);\n const decodedSession = {\n ...value,\n decodedToken: decodedToken,\n };\n\n this.storage.set(decodedSession);\n this.notifySubscribers(decodedSession);\n }\n\n /**\n * Removes the session from the underlying storage and notifies subscribers\n */\n remove(): void {\n this.storage.remove();\n this.notifySubscribers(null);\n }\n\n /**\n * Subscribe to session changes\n * @param callback - Function that will be called when the session changes\n * @returns An unsubscribe function to remove this subscription\n */\n onChange(callback: SessionChangeCallback) {\n this.subscribers.add(callback);\n\n return () => {\n this.subscribers.delete(callback);\n };\n }\n\n /**\n * Notify all subscribers of a session change\n * @param session - The new session value or null if removed\n */\n private notifySubscribers(session: Session | null): void {\n for (const subscriber of this.subscribers) {\n try {\n subscriber(session);\n } catch (error) {\n console.error('Error notifying subscriber:', error);\n }\n }\n }\n}\n\n/**\n * Detects the best available storage implementation for the current environment.\n *\n * The detection process follows this order:\n * 1. Try to use localStorage if we're in a browser environment\n * 2. Fall back to in-memory storage if localStorage isn't available\n *\n * @returns The best available storage implementation as a SessionStorageBackend\n */\nexport const detectStorage = (): SessionStorageBackend => {\n if (typeof window !== 'undefined') {\n return new LocalStorage();\n }\n return new MemoryStorage();\n};\n"],"names":[],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- !function(t,s){"object"==typeof exports&&"undefined"!=typeof module?s(exports):"function"==typeof define&&define.amd?define(["exports"],s):s((t="undefined"!=typeof globalThis?globalThis:t||self).NhostJs={})}(this,(function(t){"use strict";function s(t=[]){return t.reduceRight(((t,s)=>s(t)),fetch)}class e extends Error{body;status;headers;constructor(t,s,e){super(function(t){if(t&&"string"==typeof t)return t;if(t&&"object"==typeof t){const s=t;if("message"in s&&"string"==typeof s.message)return s.message;if("error"in s&&"string"==typeof s.error)return s.error;if("error"in s&&s.error&&"object"==typeof s.error){const t=s.error;if("message"in t&&"string"==typeof t.message)return t.message}if("errors"in s&&Array.isArray(s.errors)){const t=s.errors.filter((t=>"object"==typeof t&&null!==t&&"message"in t&&"string"==typeof t.message)).map((t=>t.message));if(t.length>0)return t.join(", ")}}return"An unexpected error occurred"}(t)),this.body=t,this.status=s,this.headers=e}}const a=t=>s=>async(e,a={})=>{const r=new Headers(a.headers||{});if(r.has("Authorization"))return s(e,a);const i=t.get();if(i?.accessToken){const t={...a,headers:n(r,i)};return s(e,t)}return s(e,a)};function n(t,s){return s.accessToken&&t.set("Authorization",`Bearer ${s.accessToken}`),t}const r="undefined"!=typeof navigator&&navigator.locks?navigator.locks:new class{async request(t,s,e){return e()}},i=async(t,s,e=60)=>{try{return await o(t,s,e)}catch(a){try{return console.warn("error refreshing session, retrying:",a),await o(t,s,e)}catch(n){const t=n;return 401===t?.status&&(console.error("session probably expired"),s.remove()),null}}},o=async(t,s,e=60)=>{const{session:a,needsRefresh:n}=await r.request("nhostSessionLock",{mode:"shared"},(async()=>u(s,e)));if(!a)return null;if(!n)return a;return await r.request("nhostSessionLock",{mode:"exclusive"},(async()=>{const{session:a,needsRefresh:n,sessionExpired:r}=u(s,e);if(!a)return null;if(!n)return a;try{const e=await t.refreshToken({refreshToken:a.refreshToken});return s.set(e.body),e.body}catch(i){if(!r)return a;throw i}}))},u=(t,s=60)=>{const e=t.get();if(!e)return{session:null,needsRefresh:!1,sessionExpired:!1};if(!e.decodedToken||!e.decodedToken.exp)return{session:e,needsRefresh:!0,sessionExpired:!0};if(0===s)return{session:e,needsRefresh:!0,sessionExpired:!1};const a=Date.now();return e.decodedToken.exp-a>1e3*s?{session:e,needsRefresh:!1,sessionExpired:!1}:{session:e,needsRefresh:!0,sessionExpired:e.decodedToken.exp<a}},d=(t,s,e)=>{const{marginSeconds:a=60}={};return e=>async(n,r={})=>{if(function(t,s){const e=new Headers(s.headers||{});if(e.has("Authorization"))return!0;if(t.endsWith("/v1/token"))return!0;return!1}(n,r))return e(n,r);try{await i(t,s,a)}catch{}return e(n,r)}};const c=t=>s=>async(e,a)=>{const n=await s(e,a);try{if(e.endsWith("/signout"))return t.remove(),n;if(e.endsWith("/token")||e.includes("/signin/")||e.includes("/signup/")){const s=n.clone(),e=await s.json().catch((()=>null));if(e){const s=(t=>"string"==typeof t?null:"session"in t?t.session||null:"accessToken"in t&&"refreshToken"in t&&"user"in t?t:null)(e);s?.accessToken&&s.refreshToken&&t.set(s)}}}catch(r){console.warn("Error in session response middleware:",r)}return n},h=t=>t.startsWith("{")&&t.endsWith("}"),l=t=>t&&"{}"!==t?t.slice(1,-1).split(",").map((t=>t.trim().replace(/^"(.*)"$/,"$1"))):[];class p{storageKey;constructor(t){this.storageKey=t?.storageKey||"nhostSession"}get(){try{const t=window.localStorage.getItem(this.storageKey);return t?JSON.parse(t):null}catch{return this.remove(),null}}set(t){window.localStorage.setItem(this.storageKey,JSON.stringify(t))}remove(){window.localStorage.removeItem(this.storageKey)}}class w{session=null;get(){return this.session}set(t){this.session=t}remove(){this.session=null}}class y{storage;subscribers=new Set;constructor(t){this.storage=t}get(){return this.storage.get()}set(t){const s=(t=>{const s=t.split(".");if(3!==s.length||!s[1])throw new Error("Invalid access token format");const e=JSON.parse("undefined"!=typeof atob?atob(s[1]):Buffer.from(s[1],"base64").toString("utf-8")),a="number"==typeof e.iat?1e3*e.iat:void 0,n="number"==typeof e.exp?1e3*e.exp:void 0,r=e["https://hasura.io/jwt/claims"],i=r?Object.entries(r).reduce(((t,[s,e])=>("string"==typeof e&&h(e)?t[s]=l(e):t[s]=e,t)),{}):void 0;return{...e,iat:a,exp:n,"https://hasura.io/jwt/claims":i}})(t.accessToken),e={...t,decodedToken:s};this.storage.set(e),this.notifySubscribers(e)}remove(){this.storage.remove(),this.notifySubscribers(null)}onChange(t){return this.subscribers.add(t),()=>{this.subscribers.delete(t)}}notifySubscribers(t){for(const e of this.subscribers)try{e(t)}catch(s){console.error("Error notifying subscriber:",s)}}}const f=()=>"undefined"!=typeof window?new p:new w,S=({auth:t,storage:s,graphql:e,functions:n,sessionStorage:r})=>{const i=[d(t,r),c(r),a(r)];for(const a of i)t.pushChainFunction(a),s.pushChainFunction(a),e.pushChainFunction(a),n.pushChainFunction(a)},g=({auth:t,storage:s,graphql:e,functions:n,sessionStorage:r})=>{const i=[c(r),a(r)];for(const a of i)t.pushChainFunction(a),s.pushChainFunction(a),e.pushChainFunction(a),n.pushChainFunction(a)};class O{auth;storage;graphql;functions;sessionStorage;constructor(t,s,e,a,n){this.auth=t,this.storage=s,this.graphql=e,this.functions=a,this.sessionStorage=n}getUserSession(){return this.sessionStorage.get()}async refreshSession(t=60){return i(this.auth,this.sessionStorage,t)}clearSession(){this.sessionStorage.remove()}}function b(t={}){const{subdomain:a,region:n,authUrl:r,storageUrl:i,graphqlUrl:o,functionsUrl:u,storage:d=f(),configure:c=[]}=t,h=new y(d),l=m("auth",a,n,r),p=m("storage",a,n,i),w=m("graphql",a,n,o),S=m("functions",a,n,u),g=((t,a=[])=>{let n=s(a);return{baseURL:t,pushChainFunction:t=>{a.push(t),n=s(a)},getJWKs:async s=>{const a=`${t}/.well-known/jwks.json`,r=await n(a,{...s,method:"GET",headers:{...s?.headers}});if(r.status>=300){const t=[412].includes(r.status)?null:await r.text(),s=t?JSON.parse(t):{};throw new e(s,r.status,r.headers)}const i=[204,205,304].includes(r.status)?null:await r.text();return{body:i?JSON.parse(i):{},status:r.status,headers:r.headers}},elevateWebauthn:async s=>{const a=`${t}/elevate/webauthn`,r=await n(a,{...s,method:"POST",headers:{...s?.headers}});if(r.status>=300){const t=[412].includes(r.status)?null:await r.text(),s=t?JSON.parse(t):{};throw new e(s,r.status,r.headers)}const i=[204,205,304].includes(r.status)?null:await r.text();return{body:i?JSON.parse(i):{},status:r.status,headers:r.headers}},verifyElevateWebauthn:async(s,a)=>{const r=`${t}/elevate/webauthn/verify`,i=await n(r,{...a,method:"POST",headers:{"Content-Type":"application/json",...a?.headers},body:JSON.stringify(s)});if(i.status>=300){const t=[412].includes(i.status)?null:await i.text(),s=t?JSON.parse(t):{};throw new e(s,i.status,i.headers)}const o=[204,205,304].includes(i.status)?null:await i.text();return{body:o?JSON.parse(o):{},status:i.status,headers:i.headers}},healthCheckGet:async s=>{const a=`${t}/healthz`,r=await n(a,{...s,method:"GET",headers:{...s?.headers}});if(r.status>=300){const t=[412].includes(r.status)?null:await r.text(),s=t?JSON.parse(t):{};throw new e(s,r.status,r.headers)}const i=[204,205,304].includes(r.status)?null:await r.text();return{body:i?JSON.parse(i):{},status:r.status,headers:r.headers}},healthCheckHead:async s=>{const a=`${t}/healthz`,r=await n(a,{...s,method:"HEAD",headers:{...s?.headers}});if(r.status>=300){const t=[412].includes(r.status)?null:await r.text(),s=t?JSON.parse(t):{};throw new e(s,r.status,r.headers)}return{body:void 0,status:r.status,headers:r.headers}},linkIdToken:async(s,a)=>{const r=`${t}/link/idtoken`,i=await n(r,{...a,method:"POST",headers:{"Content-Type":"application/json",...a?.headers},body:JSON.stringify(s)});if(i.status>=300){const t=[412].includes(i.status)?null:await i.text(),s=t?JSON.parse(t):{};throw new e(s,i.status,i.headers)}const o=[204,205,304].includes(i.status)?null:await i.text();return{body:o?JSON.parse(o):{},status:i.status,headers:i.headers}},changeUserMfa:async s=>{const a=`${t}/mfa/totp/generate`,r=await n(a,{...s,method:"GET",headers:{...s?.headers}});if(r.status>=300){const t=[412].includes(r.status)?null:await r.text(),s=t?JSON.parse(t):{};throw new e(s,r.status,r.headers)}const i=[204,205,304].includes(r.status)?null:await r.text();return{body:i?JSON.parse(i):{},status:r.status,headers:r.headers}},createPAT:async(s,a)=>{const r=`${t}/pat`,i=await n(r,{...a,method:"POST",headers:{"Content-Type":"application/json",...a?.headers},body:JSON.stringify(s)});if(i.status>=300){const t=[412].includes(i.status)?null:await i.text(),s=t?JSON.parse(t):{};throw new e(s,i.status,i.headers)}const o=[204,205,304].includes(i.status)?null:await i.text();return{body:o?JSON.parse(o):{},status:i.status,headers:i.headers}},signInAnonymous:async(s,a)=>{const r=`${t}/signin/anonymous`,i=await n(r,{...a,method:"POST",headers:{"Content-Type":"application/json",...a?.headers},body:JSON.stringify(s)});if(i.status>=300){const t=[412].includes(i.status)?null:await i.text(),s=t?JSON.parse(t):{};throw new e(s,i.status,i.headers)}const o=[204,205,304].includes(i.status)?null:await i.text();return{body:o?JSON.parse(o):{},status:i.status,headers:i.headers}},signInEmailPassword:async(s,a)=>{const r=`${t}/signin/email-password`,i=await n(r,{...a,method:"POST",headers:{"Content-Type":"application/json",...a?.headers},body:JSON.stringify(s)});if(i.status>=300){const t=[412].includes(i.status)?null:await i.text(),s=t?JSON.parse(t):{};throw new e(s,i.status,i.headers)}const o=[204,205,304].includes(i.status)?null:await i.text();return{body:o?JSON.parse(o):{},status:i.status,headers:i.headers}},signInIdToken:async(s,a)=>{const r=`${t}/signin/idtoken`,i=await n(r,{...a,method:"POST",headers:{"Content-Type":"application/json",...a?.headers},body:JSON.stringify(s)});if(i.status>=300){const t=[412].includes(i.status)?null:await i.text(),s=t?JSON.parse(t):{};throw new e(s,i.status,i.headers)}const o=[204,205,304].includes(i.status)?null:await i.text();return{body:o?JSON.parse(o):{},status:i.status,headers:i.headers}},verifySignInMfaTotp:async(s,a)=>{const r=`${t}/signin/mfa/totp`,i=await n(r,{...a,method:"POST",headers:{"Content-Type":"application/json",...a?.headers},body:JSON.stringify(s)});if(i.status>=300){const t=[412].includes(i.status)?null:await i.text(),s=t?JSON.parse(t):{};throw new e(s,i.status,i.headers)}const o=[204,205,304].includes(i.status)?null:await i.text();return{body:o?JSON.parse(o):{},status:i.status,headers:i.headers}},signInOTPEmail:async(s,a)=>{const r=`${t}/signin/otp/email`,i=await n(r,{...a,method:"POST",headers:{"Content-Type":"application/json",...a?.headers},body:JSON.stringify(s)});if(i.status>=300){const t=[412].includes(i.status)?null:await i.text(),s=t?JSON.parse(t):{};throw new e(s,i.status,i.headers)}const o=[204,205,304].includes(i.status)?null:await i.text();return{body:o?JSON.parse(o):{},status:i.status,headers:i.headers}},verifySignInOTPEmail:async(s,a)=>{const r=`${t}/signin/otp/email/verify`,i=await n(r,{...a,method:"POST",headers:{"Content-Type":"application/json",...a?.headers},body:JSON.stringify(s)});if(i.status>=300){const t=[412].includes(i.status)?null:await i.text(),s=t?JSON.parse(t):{};throw new e(s,i.status,i.headers)}const o=[204,205,304].includes(i.status)?null:await i.text();return{body:o?JSON.parse(o):{},status:i.status,headers:i.headers}},signInPasswordlessEmail:async(s,a)=>{const r=`${t}/signin/passwordless/email`,i=await n(r,{...a,method:"POST",headers:{"Content-Type":"application/json",...a?.headers},body:JSON.stringify(s)});if(i.status>=300){const t=[412].includes(i.status)?null:await i.text(),s=t?JSON.parse(t):{};throw new e(s,i.status,i.headers)}const o=[204,205,304].includes(i.status)?null:await i.text();return{body:o?JSON.parse(o):{},status:i.status,headers:i.headers}},signInPasswordlessSms:async(s,a)=>{const r=`${t}/signin/passwordless/sms`,i=await n(r,{...a,method:"POST",headers:{"Content-Type":"application/json",...a?.headers},body:JSON.stringify(s)});if(i.status>=300){const t=[412].includes(i.status)?null:await i.text(),s=t?JSON.parse(t):{};throw new e(s,i.status,i.headers)}const o=[204,205,304].includes(i.status)?null:await i.text();return{body:o?JSON.parse(o):{},status:i.status,headers:i.headers}},verifySignInPasswordlessSms:async(s,a)=>{const r=`${t}/signin/passwordless/sms/otp`,i=await n(r,{...a,method:"POST",headers:{"Content-Type":"application/json",...a?.headers},body:JSON.stringify(s)});if(i.status>=300){const t=[412].includes(i.status)?null:await i.text(),s=t?JSON.parse(t):{};throw new e(s,i.status,i.headers)}const o=[204,205,304].includes(i.status)?null:await i.text();return{body:o?JSON.parse(o):{},status:i.status,headers:i.headers}},signInPAT:async(s,a)=>{const r=`${t}/signin/pat`,i=await n(r,{...a,method:"POST",headers:{"Content-Type":"application/json",...a?.headers},body:JSON.stringify(s)});if(i.status>=300){const t=[412].includes(i.status)?null:await i.text(),s=t?JSON.parse(t):{};throw new e(s,i.status,i.headers)}const o=[204,205,304].includes(i.status)?null:await i.text();return{body:o?JSON.parse(o):{},status:i.status,headers:i.headers}},signInProviderURL:(s,e)=>{const a=e&&Object.entries(e).flatMap((([t,s])=>{if("providerSpecificParams"===t)return"object"!=typeof s||null===s||Array.isArray(s)?[`${t}=${encodeURIComponent(String(s))}`]:Object.entries(s).map((([t,s])=>`${t}=${encodeURIComponent(String(s))}`));const e=Array.isArray(s)?s.join(","):"object"==typeof s&&null!==s?JSON.stringify(s):String(s);return[`${t}=${encodeURIComponent(e)}`]})).join("&");return a?`${t}/signin/provider/${s}?${a}`:`${t}/signin/provider/${s}`},getProviderTokens:async(s,a)=>{const r=`${t}/signin/provider/${s}/callback/tokens`,i=await n(r,{...a,method:"GET",headers:{...a?.headers}});if(i.status>=300){const t=[412].includes(i.status)?null:await i.text(),s=t?JSON.parse(t):{};throw new e(s,i.status,i.headers)}const o=[204,205,304].includes(i.status)?null:await i.text();return{body:o?JSON.parse(o):{},status:i.status,headers:i.headers}},signInWebauthn:async(s,a)=>{const r=`${t}/signin/webauthn`,i=await n(r,{...a,method:"POST",headers:{"Content-Type":"application/json",...a?.headers},body:JSON.stringify(s)});if(i.status>=300){const t=[412].includes(i.status)?null:await i.text(),s=t?JSON.parse(t):{};throw new e(s,i.status,i.headers)}const o=[204,205,304].includes(i.status)?null:await i.text();return{body:o?JSON.parse(o):{},status:i.status,headers:i.headers}},verifySignInWebauthn:async(s,a)=>{const r=`${t}/signin/webauthn/verify`,i=await n(r,{...a,method:"POST",headers:{"Content-Type":"application/json",...a?.headers},body:JSON.stringify(s)});if(i.status>=300){const t=[412].includes(i.status)?null:await i.text(),s=t?JSON.parse(t):{};throw new e(s,i.status,i.headers)}const o=[204,205,304].includes(i.status)?null:await i.text();return{body:o?JSON.parse(o):{},status:i.status,headers:i.headers}},signOut:async(s,a)=>{const r=`${t}/signout`,i=await n(r,{...a,method:"POST",headers:{"Content-Type":"application/json",...a?.headers},body:JSON.stringify(s)});if(i.status>=300){const t=[412].includes(i.status)?null:await i.text(),s=t?JSON.parse(t):{};throw new e(s,i.status,i.headers)}const o=[204,205,304].includes(i.status)?null:await i.text();return{body:o?JSON.parse(o):{},status:i.status,headers:i.headers}},signUpEmailPassword:async(s,a)=>{const r=`${t}/signup/email-password`,i=await n(r,{...a,method:"POST",headers:{"Content-Type":"application/json",...a?.headers},body:JSON.stringify(s)});if(i.status>=300){const t=[412].includes(i.status)?null:await i.text(),s=t?JSON.parse(t):{};throw new e(s,i.status,i.headers)}const o=[204,205,304].includes(i.status)?null:await i.text();return{body:o?JSON.parse(o):{},status:i.status,headers:i.headers}},signUpWebauthn:async(s,a)=>{const r=`${t}/signup/webauthn`,i=await n(r,{...a,method:"POST",headers:{"Content-Type":"application/json",...a?.headers},body:JSON.stringify(s)});if(i.status>=300){const t=[412].includes(i.status)?null:await i.text(),s=t?JSON.parse(t):{};throw new e(s,i.status,i.headers)}const o=[204,205,304].includes(i.status)?null:await i.text();return{body:o?JSON.parse(o):{},status:i.status,headers:i.headers}},verifySignUpWebauthn:async(s,a)=>{const r=`${t}/signup/webauthn/verify`,i=await n(r,{...a,method:"POST",headers:{"Content-Type":"application/json",...a?.headers},body:JSON.stringify(s)});if(i.status>=300){const t=[412].includes(i.status)?null:await i.text(),s=t?JSON.parse(t):{};throw new e(s,i.status,i.headers)}const o=[204,205,304].includes(i.status)?null:await i.text();return{body:o?JSON.parse(o):{},status:i.status,headers:i.headers}},refreshToken:async(s,a)=>{const r=`${t}/token`,i=await n(r,{...a,method:"POST",headers:{"Content-Type":"application/json",...a?.headers},body:JSON.stringify(s)});if(i.status>=300){const t=[412].includes(i.status)?null:await i.text(),s=t?JSON.parse(t):{};throw new e(s,i.status,i.headers)}const o=[204,205,304].includes(i.status)?null:await i.text();return{body:o?JSON.parse(o):{},status:i.status,headers:i.headers}},refreshProviderToken:async(s,a,r)=>{const i=`${t}/token/provider/${s}`,o=await n(i,{...r,method:"POST",headers:{"Content-Type":"application/json",...r?.headers},body:JSON.stringify(a)});if(o.status>=300){const t=[412].includes(o.status)?null:await o.text(),s=t?JSON.parse(t):{};throw new e(s,o.status,o.headers)}const u=[204,205,304].includes(o.status)?null:await o.text();return{body:u?JSON.parse(u):{},status:o.status,headers:o.headers}},verifyToken:async(s,a)=>{const r=`${t}/token/verify`,i=await n(r,{...a,method:"POST",headers:{"Content-Type":"application/json",...a?.headers},body:JSON.stringify(s)});if(i.status>=300){const t=[412].includes(i.status)?null:await i.text(),s=t?JSON.parse(t):{};throw new e(s,i.status,i.headers)}const o=[204,205,304].includes(i.status)?null:await i.text();return{body:o?JSON.parse(o):{},status:i.status,headers:i.headers}},getUser:async s=>{const a=`${t}/user`,r=await n(a,{...s,method:"GET",headers:{...s?.headers}});if(r.status>=300){const t=[412].includes(r.status)?null:await r.text(),s=t?JSON.parse(t):{};throw new e(s,r.status,r.headers)}const i=[204,205,304].includes(r.status)?null:await r.text();return{body:i?JSON.parse(i):{},status:r.status,headers:r.headers}},deanonymizeUser:async(s,a)=>{const r=`${t}/user/deanonymize`,i=await n(r,{...a,method:"POST",headers:{"Content-Type":"application/json",...a?.headers},body:JSON.stringify(s)});if(i.status>=300){const t=[412].includes(i.status)?null:await i.text(),s=t?JSON.parse(t):{};throw new e(s,i.status,i.headers)}const o=[204,205,304].includes(i.status)?null:await i.text();return{body:o?JSON.parse(o):{},status:i.status,headers:i.headers}},changeUserEmail:async(s,a)=>{const r=`${t}/user/email/change`,i=await n(r,{...a,method:"POST",headers:{"Content-Type":"application/json",...a?.headers},body:JSON.stringify(s)});if(i.status>=300){const t=[412].includes(i.status)?null:await i.text(),s=t?JSON.parse(t):{};throw new e(s,i.status,i.headers)}const o=[204,205,304].includes(i.status)?null:await i.text();return{body:o?JSON.parse(o):{},status:i.status,headers:i.headers}},sendVerificationEmail:async(s,a)=>{const r=`${t}/user/email/send-verification-email`,i=await n(r,{...a,method:"POST",headers:{"Content-Type":"application/json",...a?.headers},body:JSON.stringify(s)});if(i.status>=300){const t=[412].includes(i.status)?null:await i.text(),s=t?JSON.parse(t):{};throw new e(s,i.status,i.headers)}const o=[204,205,304].includes(i.status)?null:await i.text();return{body:o?JSON.parse(o):{},status:i.status,headers:i.headers}},verifyChangeUserMfa:async(s,a)=>{const r=`${t}/user/mfa`,i=await n(r,{...a,method:"POST",headers:{"Content-Type":"application/json",...a?.headers},body:JSON.stringify(s)});if(i.status>=300){const t=[412].includes(i.status)?null:await i.text(),s=t?JSON.parse(t):{};throw new e(s,i.status,i.headers)}const o=[204,205,304].includes(i.status)?null:await i.text();return{body:o?JSON.parse(o):{},status:i.status,headers:i.headers}},changeUserPassword:async(s,a)=>{const r=`${t}/user/password`,i=await n(r,{...a,method:"POST",headers:{"Content-Type":"application/json",...a?.headers},body:JSON.stringify(s)});if(i.status>=300){const t=[412].includes(i.status)?null:await i.text(),s=t?JSON.parse(t):{};throw new e(s,i.status,i.headers)}const o=[204,205,304].includes(i.status)?null:await i.text();return{body:o?JSON.parse(o):{},status:i.status,headers:i.headers}},sendPasswordResetEmail:async(s,a)=>{const r=`${t}/user/password/reset`,i=await n(r,{...a,method:"POST",headers:{"Content-Type":"application/json",...a?.headers},body:JSON.stringify(s)});if(i.status>=300){const t=[412].includes(i.status)?null:await i.text(),s=t?JSON.parse(t):{};throw new e(s,i.status,i.headers)}const o=[204,205,304].includes(i.status)?null:await i.text();return{body:o?JSON.parse(o):{},status:i.status,headers:i.headers}},addSecurityKey:async s=>{const a=`${t}/user/webauthn/add`,r=await n(a,{...s,method:"POST",headers:{...s?.headers}});if(r.status>=300){const t=[412].includes(r.status)?null:await r.text(),s=t?JSON.parse(t):{};throw new e(s,r.status,r.headers)}const i=[204,205,304].includes(r.status)?null:await r.text();return{body:i?JSON.parse(i):{},status:r.status,headers:r.headers}},verifyAddSecurityKey:async(s,a)=>{const r=`${t}/user/webauthn/verify`,i=await n(r,{...a,method:"POST",headers:{"Content-Type":"application/json",...a?.headers},body:JSON.stringify(s)});if(i.status>=300){const t=[412].includes(i.status)?null:await i.text(),s=t?JSON.parse(t):{};throw new e(s,i.status,i.headers)}const o=[204,205,304].includes(i.status)?null:await i.text();return{body:o?JSON.parse(o):{},status:i.status,headers:i.headers}},verifyTicketURL:s=>{const e=s&&Object.entries(s).flatMap((([t,s])=>{const e=Array.isArray(s)?s.join(","):"object"==typeof s&&null!==s?JSON.stringify(s):String(s);return[`${t}=${encodeURIComponent(e)}`]})).join("&");return e?`${t}/verify?${e}`:`${t}/verify`},getVersion:async s=>{const a=`${t}/version`,r=await n(a,{...s,method:"GET",headers:{...s?.headers}});if(r.status>=300){const t=[412].includes(r.status)?null:await r.text(),s=t?JSON.parse(t):{};throw new e(s,r.status,r.headers)}const i=[204,205,304].includes(r.status)?null:await r.text();return{body:i?JSON.parse(i):{},status:r.status,headers:r.headers}}}})(l),b=((t,a=[])=>{let n=s(a);return{baseURL:t,pushChainFunction:t=>{a.push(t),n=s(a)},uploadFiles:async(s,a)=>{const r=`${t}/files`,i=new FormData,o="undefined"!=typeof navigator&&"ReactNative"===navigator.product;void 0!==s["bucket-id"]&&i.append("bucket-id",s["bucket-id"]),void 0!==s["metadata[]"]&&s["metadata[]"].forEach((t=>{o?i.append("metadata[]",{string:JSON.stringify(t),type:"application/json",name:""}):i.append("metadata[]",new Blob([JSON.stringify(t)],{type:"application/json"}),"")})),void 0!==s["file[]"]&&s["file[]"].forEach((t=>{i.append("file[]",t)}));const u=await n(r,{...a,method:"POST",body:i});if(u.status>=300){const t=[412].includes(u.status)?null:await u.text(),s=t?JSON.parse(t):{};throw new e(s,u.status,u.headers)}const d=[204,205,304].includes(u.status)?null:await u.text();return{body:d?JSON.parse(d):{},status:u.status,headers:u.headers}},deleteFile:async(s,a)=>{const r=`${t}/files/${s}`,i=await n(r,{...a,method:"DELETE",headers:{...a?.headers}});if(i.status>=300){const t=[412].includes(i.status)?null:await i.text(),s=t?JSON.parse(t):{};throw new e(s,i.status,i.headers)}return{body:void 0,status:i.status,headers:i.headers}},getFile:async(s,a,r)=>{const i=a&&Object.entries(a).flatMap((([t,s])=>{const e=Array.isArray(s)?s.join(","):"object"==typeof s&&null!==s?JSON.stringify(s):String(s);return[`${t}=${encodeURIComponent(e)}`]})).join("&"),o=i?`${t}/files/${s}?${i}`:`${t}/files/${s}`,u=await n(o,{...r,method:"GET",headers:{...r?.headers}});if(u.status>=300){const t=[412].includes(u.status)?null:await u.text(),s=t?JSON.parse(t):{};throw new e(s,u.status,u.headers)}return{body:await u.blob(),status:u.status,headers:u.headers}},getFileMetadataHeaders:async(s,a,r)=>{const i=a&&Object.entries(a).flatMap((([t,s])=>{const e=Array.isArray(s)?s.join(","):"object"==typeof s&&null!==s?JSON.stringify(s):String(s);return[`${t}=${encodeURIComponent(e)}`]})).join("&"),o=i?`${t}/files/${s}?${i}`:`${t}/files/${s}`,u=await n(o,{...r,method:"HEAD",headers:{...r?.headers}});if(u.status>=300){const t=[412].includes(u.status)?null:await u.text(),s=t?JSON.parse(t):{};throw new e(s,u.status,u.headers)}return{body:void 0,status:u.status,headers:u.headers}},replaceFile:async(s,a,r)=>{const i=`${t}/files/${s}`,o=new FormData,u="undefined"!=typeof navigator&&"ReactNative"===navigator.product;void 0!==a.metadata&&(u?o.append("metadata",{string:JSON.stringify(a.metadata),type:"application/json",name:""}):o.append("metadata",new Blob([JSON.stringify(a.metadata)],{type:"application/json"}),"")),void 0!==a.file&&o.append("file",a.file);const d=await n(i,{...r,method:"PUT",body:o});if(d.status>=300){const t=[412].includes(d.status)?null:await d.text(),s=t?JSON.parse(t):{};throw new e(s,d.status,d.headers)}const c=[204,205,304].includes(d.status)?null:await d.text();return{body:c?JSON.parse(c):{},status:d.status,headers:d.headers}},getFilePresignedURL:async(s,a)=>{const r=`${t}/files/${s}/presignedurl`,i=await n(r,{...a,method:"GET",headers:{...a?.headers}});if(i.status>=300){const t=[412].includes(i.status)?null:await i.text(),s=t?JSON.parse(t):{};throw new e(s,i.status,i.headers)}const o=[204,205,304].includes(i.status)?null:await i.text();return{body:o?JSON.parse(o):{},status:i.status,headers:i.headers}},deleteBrokenMetadata:async s=>{const a=`${t}/ops/delete-broken-metadata`,r=await n(a,{...s,method:"POST",headers:{...s?.headers}});if(r.status>=300){const t=[412].includes(r.status)?null:await r.text(),s=t?JSON.parse(t):{};throw new e(s,r.status,r.headers)}const i=[204,205,304].includes(r.status)?null:await r.text();return{body:i?JSON.parse(i):{},status:r.status,headers:r.headers}},deleteOrphanedFiles:async s=>{const a=`${t}/ops/delete-orphans`,r=await n(a,{...s,method:"POST",headers:{...s?.headers}});if(r.status>=300){const t=[412].includes(r.status)?null:await r.text(),s=t?JSON.parse(t):{};throw new e(s,r.status,r.headers)}const i=[204,205,304].includes(r.status)?null:await r.text();return{body:i?JSON.parse(i):{},status:r.status,headers:r.headers}},listBrokenMetadata:async s=>{const a=`${t}/ops/list-broken-metadata`,r=await n(a,{...s,method:"POST",headers:{...s?.headers}});if(r.status>=300){const t=[412].includes(r.status)?null:await r.text(),s=t?JSON.parse(t):{};throw new e(s,r.status,r.headers)}const i=[204,205,304].includes(r.status)?null:await r.text();return{body:i?JSON.parse(i):{},status:r.status,headers:r.headers}},listFilesNotUploaded:async s=>{const a=`${t}/ops/list-not-uploaded`,r=await n(a,{...s,method:"POST",headers:{...s?.headers}});if(r.status>=300){const t=[412].includes(r.status)?null:await r.text(),s=t?JSON.parse(t):{};throw new e(s,r.status,r.headers)}const i=[204,205,304].includes(r.status)?null:await r.text();return{body:i?JSON.parse(i):{},status:r.status,headers:r.headers}},listOrphanedFiles:async s=>{const a=`${t}/ops/list-orphans`,r=await n(a,{...s,method:"POST",headers:{...s?.headers}});if(r.status>=300){const t=[412].includes(r.status)?null:await r.text(),s=t?JSON.parse(t):{};throw new e(s,r.status,r.headers)}const i=[204,205,304].includes(r.status)?null:await r.text();return{body:i?JSON.parse(i):{},status:r.status,headers:r.headers}},getVersion:async s=>{const a=`${t}/version`,r=await n(a,{...s,method:"GET",headers:{...s?.headers}});if(r.status>=300){const t=[412].includes(r.status)?null:await r.text(),s=t?JSON.parse(t):{};throw new e(s,r.status,r.headers)}const i=[204,205,304].includes(r.status)?null:await r.text();return{body:i?JSON.parse(i):{},status:r.status,headers:r.headers}}}})(p,[]),N=((t,a=[])=>{let n=s(a);const r=async(s,a)=>{const r=await n(`${t}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s),...a}),i=await r.text(),o=i?JSON.parse(i):{},u={body:o,status:r.status,headers:r.headers};if(o.errors)throw new e(o,r.status,r.headers);return u};return{request:function(t,s,e){if("object"==typeof t&&"kind"in t){const a=t.definitions[0],n={query:t.loc?.source.body||"",variables:s,operationName:a&&"name"in a?a.name?.value:void 0};return r(n,e)}return r(t,s)},url:t,pushChainFunction:t=>{a.push(t),n=s(a)}}})(w,[]),J=((t,a=[])=>{let n=s(a);const r=async(s,a)=>{const r=await n(`${t}${s}`,a);let i;if(i=r.headers.get("content-type")?.includes("application/json")?await r.json():r.headers.get("content-type")?.startsWith("text/")?await r.text():await r.blob(),!r.ok)throw new e(i,r.status,r.headers);return{status:r.status,body:i,headers:r.headers}};return{baseURL:t,fetch:r,post:async(t,s,e={})=>{const a={...e,method:"POST",headers:{Accept:"application/json","Content-Type":"application/json",...e.headers},body:s?JSON.stringify(s):void 0};return r(t,a)},pushChainFunction:t=>{a.push(t),n=s(a)}}})(S,[]);for(const s of c)s({auth:g,storage:b,graphql:N,functions:J,sessionStorage:h});return new O(g,b,N,J,h)}const m=(t,s,e,a)=>a||(s&&e?`https://${s}.${t}.${e}.nhost.run/v1`:`https://local.${t}.local.nhost.run/v1`);t.createClient=function(t={}){const s=t.storage??f();return b({...t,storage:s,configure:[S,...t.configure??[]]})},t.createNhostClient=b,t.createServerClient=function(t){return b({...t,configure:[g,...t.configure??[]]})},t.generateServiceUrl=m,t.withAdminSession=function(t){return({storage:s,graphql:e,functions:a})=>{const n=(r=t,t=>async(s,e={})=>{const a=new Headers(e.headers||{});if(a.has("x-hasura-admin-secret")||a.set("x-hasura-admin-secret",r.adminSecret),r.role&&!a.has("x-hasura-role")&&a.set("x-hasura-role",r.role),r.sessionVariables)for(const[t,n]of Object.entries(r.sessionVariables)){const s=t.startsWith("x-hasura-")?t:`x-hasura-${t}`;a.has(s)||a.set(s,n)}return t(s,{...e,headers:a})});var r;s.pushChainFunction(n),e.pushChainFunction(n),a.pushChainFunction(n)}},t.withClientSideSessionMiddleware=S,t.withServerSideSessionMiddleware=g,Object.defineProperty(t,Symbol.toStringTag,{value:"Module"})}));
1
+ !function(t,s){"object"==typeof exports&&"undefined"!=typeof module?s(exports):"function"==typeof define&&define.amd?define(["exports"],s):s((t="undefined"!=typeof globalThis?globalThis:t||self).NhostJs={})}(this,(function(t){"use strict";function s(t=[]){return t.reduceRight(((t,s)=>s(t)),fetch)}class e extends Error{body;status;headers;constructor(t,s,e){super(function(t){if(t&&"string"==typeof t)return t;if(t&&"object"==typeof t){const s=t;if("message"in s&&"string"==typeof s.message)return s.message;if("error"in s&&"string"==typeof s.error)return s.error;if("error"in s&&s.error&&"object"==typeof s.error){const t=s.error;if("message"in t&&"string"==typeof t.message)return t.message}if("errors"in s&&Array.isArray(s.errors)){const t=s.errors.filter((t=>"object"==typeof t&&null!==t&&"message"in t&&"string"==typeof t.message)).map((t=>t.message));if(t.length>0)return t.join(", ")}}return"An unexpected error occurred"}(t)),this.body=t,this.status=s,this.headers=e}}const a=t=>s=>async(e,a={})=>{const r=new Headers(a.headers||{});if(r.has("Authorization"))return s(e,a);const i=t.get();if(i?.accessToken){const t={...a,headers:n(r,i)};return s(e,t)}return s(e,a)};function n(t,s){return s.accessToken&&t.set("Authorization",`Bearer ${s.accessToken}`),t}const r="undefined"!=typeof navigator&&navigator.locks?navigator.locks:new class{async request(t,s,e){return e()}},i=async(t,s,e=60)=>{try{return await o(t,s,e)}catch(a){try{return console.warn("error refreshing session, retrying:",a),await o(t,s,e)}catch(n){const t=n;return 401===t?.status&&(console.error("session probably expired"),s.remove()),null}}},o=async(t,s,e=60)=>{const{session:a,needsRefresh:n}=await r.request("nhostSessionLock",{mode:"shared"},(async()=>u(s,e)));if(!a)return null;if(!n)return a;return await r.request("nhostSessionLock",{mode:"exclusive"},(async()=>{const{session:a,needsRefresh:n,sessionExpired:r}=u(s,e);if(!a)return null;if(!n)return a;try{const e=await t.refreshToken({refreshToken:a.refreshToken});return s.set(e.body),e.body}catch(i){if(!r)return a;throw i}}))},u=(t,s=60)=>{const e=t.get();if(!e)return{session:null,needsRefresh:!1,sessionExpired:!1};if(!e.decodedToken||!e.decodedToken.exp)return{session:e,needsRefresh:!0,sessionExpired:!0};if(0===s)return{session:e,needsRefresh:!0,sessionExpired:!1};const a=Date.now();return e.decodedToken.exp-a>1e3*s?{session:e,needsRefresh:!1,sessionExpired:!1}:{session:e,needsRefresh:!0,sessionExpired:e.decodedToken.exp<a}},d=(t,s,e)=>{const{marginSeconds:a=60}={};return e=>async(n,r={})=>{if(function(t,s){const e=new Headers(s.headers||{});if(e.has("Authorization"))return!0;if(t.endsWith("/v1/token"))return!0;return!1}(n,r))return e(n,r);try{await i(t,s,a)}catch{}return e(n,r)}};const c=t=>s=>async(e,a)=>{const n=await s(e,a);try{if(e.endsWith("/signout"))return t.remove(),n;if(e.endsWith("/token")||e.includes("/signin/")||e.includes("/signup/")){const s=n.clone(),e=await s.json().catch((()=>null));if(e){const s=(t=>"string"==typeof t?null:"session"in t?t.session||null:"accessToken"in t&&"refreshToken"in t&&"user"in t?t:null)(e);s?.accessToken&&s.refreshToken&&t.set(s)}}}catch(r){console.warn("Error in session response middleware:",r)}return n},h=t=>{const s=t.split(".");if(3!==s.length||!s[1])throw new Error("Invalid access token format");const e=JSON.parse((t=>{let s=t.replace(/-/g,"+").replace(/_/g,"/");const e=s.length%4;e&&(s+="=".repeat(4-e));const a=atob(s),n=Uint8Array.from(a,(t=>t.charCodeAt(0)));return(new TextDecoder).decode(n)})(s[1])),a="number"==typeof e.iat?1e3*e.iat:void 0,n="number"==typeof e.exp?1e3*e.exp:void 0,r=e["https://hasura.io/jwt/claims"],i=r?Object.entries(r).reduce(((t,[s,e])=>("string"==typeof e&&l(e)?t[s]=p(e):t[s]=e,t)),{}):void 0;return{...e,iat:a,exp:n,"https://hasura.io/jwt/claims":i}},l=t=>t.startsWith("{")&&t.endsWith("}"),p=t=>t&&"{}"!==t?t.slice(1,-1).split(",").map((t=>t.trim().replace(/^"(.*)"$/,"$1"))):[];class w{storageKey;constructor(t){this.storageKey=t?.storageKey||"nhostSession"}get(){try{const t=window.localStorage.getItem(this.storageKey);return t?JSON.parse(t):null}catch{return this.remove(),null}}set(t){window.localStorage.setItem(this.storageKey,JSON.stringify(t))}remove(){window.localStorage.removeItem(this.storageKey)}}class y{session=null;get(){return this.session}set(t){this.session=t}remove(){this.session=null}}class f{storage;subscribers=new Set;constructor(t){this.storage=t}get(){return this.storage.get()}set(t){const s=h(t.accessToken),e={...t,decodedToken:s};this.storage.set(e),this.notifySubscribers(e)}remove(){this.storage.remove(),this.notifySubscribers(null)}onChange(t){return this.subscribers.add(t),()=>{this.subscribers.delete(t)}}notifySubscribers(t){for(const e of this.subscribers)try{e(t)}catch(s){console.error("Error notifying subscriber:",s)}}}const S=()=>"undefined"!=typeof window?new w:new y,g=({auth:t,storage:s,graphql:e,functions:n,sessionStorage:r})=>{const i=[d(t,r),c(r),a(r)];for(const a of i)t.pushChainFunction(a),s.pushChainFunction(a),e.pushChainFunction(a),n.pushChainFunction(a)},O=({auth:t,storage:s,graphql:e,functions:n,sessionStorage:r})=>{const i=[c(r),a(r)];for(const a of i)t.pushChainFunction(a),s.pushChainFunction(a),e.pushChainFunction(a),n.pushChainFunction(a)};class b{auth;storage;graphql;functions;sessionStorage;constructor(t,s,e,a,n){this.auth=t,this.storage=s,this.graphql=e,this.functions=a,this.sessionStorage=n}getUserSession(){return this.sessionStorage.get()}async refreshSession(t=60){return i(this.auth,this.sessionStorage,t)}clearSession(){this.sessionStorage.remove()}}function m(t={}){const{subdomain:a,region:n,authUrl:r,storageUrl:i,graphqlUrl:o,functionsUrl:u,storage:d=S(),configure:c=[]}=t,h=new f(d),l=N("auth",a,n,r),p=N("storage",a,n,i),w=N("graphql",a,n,o),y=N("functions",a,n,u),g=((t,a=[])=>{let n=s(a);return{baseURL:t,pushChainFunction:t=>{a.push(t),n=s(a)},getJWKs:async s=>{const a=`${t}/.well-known/jwks.json`,r=await n(a,{...s,method:"GET",headers:{...s?.headers}});if(r.status>=300){const t=[412].includes(r.status)?null:await r.text(),s=t?JSON.parse(t):{};throw new e(s,r.status,r.headers)}const i=[204,205,304].includes(r.status)?null:await r.text();return{body:i?JSON.parse(i):{},status:r.status,headers:r.headers}},elevateWebauthn:async s=>{const a=`${t}/elevate/webauthn`,r=await n(a,{...s,method:"POST",headers:{...s?.headers}});if(r.status>=300){const t=[412].includes(r.status)?null:await r.text(),s=t?JSON.parse(t):{};throw new e(s,r.status,r.headers)}const i=[204,205,304].includes(r.status)?null:await r.text();return{body:i?JSON.parse(i):{},status:r.status,headers:r.headers}},verifyElevateWebauthn:async(s,a)=>{const r=`${t}/elevate/webauthn/verify`,i=await n(r,{...a,method:"POST",headers:{"Content-Type":"application/json",...a?.headers},body:JSON.stringify(s)});if(i.status>=300){const t=[412].includes(i.status)?null:await i.text(),s=t?JSON.parse(t):{};throw new e(s,i.status,i.headers)}const o=[204,205,304].includes(i.status)?null:await i.text();return{body:o?JSON.parse(o):{},status:i.status,headers:i.headers}},healthCheckGet:async s=>{const a=`${t}/healthz`,r=await n(a,{...s,method:"GET",headers:{...s?.headers}});if(r.status>=300){const t=[412].includes(r.status)?null:await r.text(),s=t?JSON.parse(t):{};throw new e(s,r.status,r.headers)}const i=[204,205,304].includes(r.status)?null:await r.text();return{body:i?JSON.parse(i):{},status:r.status,headers:r.headers}},healthCheckHead:async s=>{const a=`${t}/healthz`,r=await n(a,{...s,method:"HEAD",headers:{...s?.headers}});if(r.status>=300){const t=[412].includes(r.status)?null:await r.text(),s=t?JSON.parse(t):{};throw new e(s,r.status,r.headers)}return{body:void 0,status:r.status,headers:r.headers}},linkIdToken:async(s,a)=>{const r=`${t}/link/idtoken`,i=await n(r,{...a,method:"POST",headers:{"Content-Type":"application/json",...a?.headers},body:JSON.stringify(s)});if(i.status>=300){const t=[412].includes(i.status)?null:await i.text(),s=t?JSON.parse(t):{};throw new e(s,i.status,i.headers)}const o=[204,205,304].includes(i.status)?null:await i.text();return{body:o?JSON.parse(o):{},status:i.status,headers:i.headers}},changeUserMfa:async s=>{const a=`${t}/mfa/totp/generate`,r=await n(a,{...s,method:"GET",headers:{...s?.headers}});if(r.status>=300){const t=[412].includes(r.status)?null:await r.text(),s=t?JSON.parse(t):{};throw new e(s,r.status,r.headers)}const i=[204,205,304].includes(r.status)?null:await r.text();return{body:i?JSON.parse(i):{},status:r.status,headers:r.headers}},createPAT:async(s,a)=>{const r=`${t}/pat`,i=await n(r,{...a,method:"POST",headers:{"Content-Type":"application/json",...a?.headers},body:JSON.stringify(s)});if(i.status>=300){const t=[412].includes(i.status)?null:await i.text(),s=t?JSON.parse(t):{};throw new e(s,i.status,i.headers)}const o=[204,205,304].includes(i.status)?null:await i.text();return{body:o?JSON.parse(o):{},status:i.status,headers:i.headers}},signInAnonymous:async(s,a)=>{const r=`${t}/signin/anonymous`,i=await n(r,{...a,method:"POST",headers:{"Content-Type":"application/json",...a?.headers},body:JSON.stringify(s)});if(i.status>=300){const t=[412].includes(i.status)?null:await i.text(),s=t?JSON.parse(t):{};throw new e(s,i.status,i.headers)}const o=[204,205,304].includes(i.status)?null:await i.text();return{body:o?JSON.parse(o):{},status:i.status,headers:i.headers}},signInEmailPassword:async(s,a)=>{const r=`${t}/signin/email-password`,i=await n(r,{...a,method:"POST",headers:{"Content-Type":"application/json",...a?.headers},body:JSON.stringify(s)});if(i.status>=300){const t=[412].includes(i.status)?null:await i.text(),s=t?JSON.parse(t):{};throw new e(s,i.status,i.headers)}const o=[204,205,304].includes(i.status)?null:await i.text();return{body:o?JSON.parse(o):{},status:i.status,headers:i.headers}},signInIdToken:async(s,a)=>{const r=`${t}/signin/idtoken`,i=await n(r,{...a,method:"POST",headers:{"Content-Type":"application/json",...a?.headers},body:JSON.stringify(s)});if(i.status>=300){const t=[412].includes(i.status)?null:await i.text(),s=t?JSON.parse(t):{};throw new e(s,i.status,i.headers)}const o=[204,205,304].includes(i.status)?null:await i.text();return{body:o?JSON.parse(o):{},status:i.status,headers:i.headers}},verifySignInMfaTotp:async(s,a)=>{const r=`${t}/signin/mfa/totp`,i=await n(r,{...a,method:"POST",headers:{"Content-Type":"application/json",...a?.headers},body:JSON.stringify(s)});if(i.status>=300){const t=[412].includes(i.status)?null:await i.text(),s=t?JSON.parse(t):{};throw new e(s,i.status,i.headers)}const o=[204,205,304].includes(i.status)?null:await i.text();return{body:o?JSON.parse(o):{},status:i.status,headers:i.headers}},signInOTPEmail:async(s,a)=>{const r=`${t}/signin/otp/email`,i=await n(r,{...a,method:"POST",headers:{"Content-Type":"application/json",...a?.headers},body:JSON.stringify(s)});if(i.status>=300){const t=[412].includes(i.status)?null:await i.text(),s=t?JSON.parse(t):{};throw new e(s,i.status,i.headers)}const o=[204,205,304].includes(i.status)?null:await i.text();return{body:o?JSON.parse(o):{},status:i.status,headers:i.headers}},verifySignInOTPEmail:async(s,a)=>{const r=`${t}/signin/otp/email/verify`,i=await n(r,{...a,method:"POST",headers:{"Content-Type":"application/json",...a?.headers},body:JSON.stringify(s)});if(i.status>=300){const t=[412].includes(i.status)?null:await i.text(),s=t?JSON.parse(t):{};throw new e(s,i.status,i.headers)}const o=[204,205,304].includes(i.status)?null:await i.text();return{body:o?JSON.parse(o):{},status:i.status,headers:i.headers}},signInPasswordlessEmail:async(s,a)=>{const r=`${t}/signin/passwordless/email`,i=await n(r,{...a,method:"POST",headers:{"Content-Type":"application/json",...a?.headers},body:JSON.stringify(s)});if(i.status>=300){const t=[412].includes(i.status)?null:await i.text(),s=t?JSON.parse(t):{};throw new e(s,i.status,i.headers)}const o=[204,205,304].includes(i.status)?null:await i.text();return{body:o?JSON.parse(o):{},status:i.status,headers:i.headers}},signInPasswordlessSms:async(s,a)=>{const r=`${t}/signin/passwordless/sms`,i=await n(r,{...a,method:"POST",headers:{"Content-Type":"application/json",...a?.headers},body:JSON.stringify(s)});if(i.status>=300){const t=[412].includes(i.status)?null:await i.text(),s=t?JSON.parse(t):{};throw new e(s,i.status,i.headers)}const o=[204,205,304].includes(i.status)?null:await i.text();return{body:o?JSON.parse(o):{},status:i.status,headers:i.headers}},verifySignInPasswordlessSms:async(s,a)=>{const r=`${t}/signin/passwordless/sms/otp`,i=await n(r,{...a,method:"POST",headers:{"Content-Type":"application/json",...a?.headers},body:JSON.stringify(s)});if(i.status>=300){const t=[412].includes(i.status)?null:await i.text(),s=t?JSON.parse(t):{};throw new e(s,i.status,i.headers)}const o=[204,205,304].includes(i.status)?null:await i.text();return{body:o?JSON.parse(o):{},status:i.status,headers:i.headers}},signInPAT:async(s,a)=>{const r=`${t}/signin/pat`,i=await n(r,{...a,method:"POST",headers:{"Content-Type":"application/json",...a?.headers},body:JSON.stringify(s)});if(i.status>=300){const t=[412].includes(i.status)?null:await i.text(),s=t?JSON.parse(t):{};throw new e(s,i.status,i.headers)}const o=[204,205,304].includes(i.status)?null:await i.text();return{body:o?JSON.parse(o):{},status:i.status,headers:i.headers}},signInProviderURL:(s,e)=>{const a=e&&Object.entries(e).flatMap((([t,s])=>{if("providerSpecificParams"===t)return"object"!=typeof s||null===s||Array.isArray(s)?[`${t}=${encodeURIComponent(String(s))}`]:Object.entries(s).map((([t,s])=>`${t}=${encodeURIComponent(String(s))}`));const e=Array.isArray(s)?s.join(","):"object"==typeof s&&null!==s?JSON.stringify(s):String(s);return[`${t}=${encodeURIComponent(e)}`]})).join("&");return a?`${t}/signin/provider/${s}?${a}`:`${t}/signin/provider/${s}`},getProviderTokens:async(s,a)=>{const r=`${t}/signin/provider/${s}/callback/tokens`,i=await n(r,{...a,method:"GET",headers:{...a?.headers}});if(i.status>=300){const t=[412].includes(i.status)?null:await i.text(),s=t?JSON.parse(t):{};throw new e(s,i.status,i.headers)}const o=[204,205,304].includes(i.status)?null:await i.text();return{body:o?JSON.parse(o):{},status:i.status,headers:i.headers}},signInWebauthn:async(s,a)=>{const r=`${t}/signin/webauthn`,i=await n(r,{...a,method:"POST",headers:{"Content-Type":"application/json",...a?.headers},body:JSON.stringify(s)});if(i.status>=300){const t=[412].includes(i.status)?null:await i.text(),s=t?JSON.parse(t):{};throw new e(s,i.status,i.headers)}const o=[204,205,304].includes(i.status)?null:await i.text();return{body:o?JSON.parse(o):{},status:i.status,headers:i.headers}},verifySignInWebauthn:async(s,a)=>{const r=`${t}/signin/webauthn/verify`,i=await n(r,{...a,method:"POST",headers:{"Content-Type":"application/json",...a?.headers},body:JSON.stringify(s)});if(i.status>=300){const t=[412].includes(i.status)?null:await i.text(),s=t?JSON.parse(t):{};throw new e(s,i.status,i.headers)}const o=[204,205,304].includes(i.status)?null:await i.text();return{body:o?JSON.parse(o):{},status:i.status,headers:i.headers}},signOut:async(s,a)=>{const r=`${t}/signout`,i=await n(r,{...a,method:"POST",headers:{"Content-Type":"application/json",...a?.headers},body:JSON.stringify(s)});if(i.status>=300){const t=[412].includes(i.status)?null:await i.text(),s=t?JSON.parse(t):{};throw new e(s,i.status,i.headers)}const o=[204,205,304].includes(i.status)?null:await i.text();return{body:o?JSON.parse(o):{},status:i.status,headers:i.headers}},signUpEmailPassword:async(s,a)=>{const r=`${t}/signup/email-password`,i=await n(r,{...a,method:"POST",headers:{"Content-Type":"application/json",...a?.headers},body:JSON.stringify(s)});if(i.status>=300){const t=[412].includes(i.status)?null:await i.text(),s=t?JSON.parse(t):{};throw new e(s,i.status,i.headers)}const o=[204,205,304].includes(i.status)?null:await i.text();return{body:o?JSON.parse(o):{},status:i.status,headers:i.headers}},signUpWebauthn:async(s,a)=>{const r=`${t}/signup/webauthn`,i=await n(r,{...a,method:"POST",headers:{"Content-Type":"application/json",...a?.headers},body:JSON.stringify(s)});if(i.status>=300){const t=[412].includes(i.status)?null:await i.text(),s=t?JSON.parse(t):{};throw new e(s,i.status,i.headers)}const o=[204,205,304].includes(i.status)?null:await i.text();return{body:o?JSON.parse(o):{},status:i.status,headers:i.headers}},verifySignUpWebauthn:async(s,a)=>{const r=`${t}/signup/webauthn/verify`,i=await n(r,{...a,method:"POST",headers:{"Content-Type":"application/json",...a?.headers},body:JSON.stringify(s)});if(i.status>=300){const t=[412].includes(i.status)?null:await i.text(),s=t?JSON.parse(t):{};throw new e(s,i.status,i.headers)}const o=[204,205,304].includes(i.status)?null:await i.text();return{body:o?JSON.parse(o):{},status:i.status,headers:i.headers}},refreshToken:async(s,a)=>{const r=`${t}/token`,i=await n(r,{...a,method:"POST",headers:{"Content-Type":"application/json",...a?.headers},body:JSON.stringify(s)});if(i.status>=300){const t=[412].includes(i.status)?null:await i.text(),s=t?JSON.parse(t):{};throw new e(s,i.status,i.headers)}const o=[204,205,304].includes(i.status)?null:await i.text();return{body:o?JSON.parse(o):{},status:i.status,headers:i.headers}},refreshProviderToken:async(s,a,r)=>{const i=`${t}/token/provider/${s}`,o=await n(i,{...r,method:"POST",headers:{"Content-Type":"application/json",...r?.headers},body:JSON.stringify(a)});if(o.status>=300){const t=[412].includes(o.status)?null:await o.text(),s=t?JSON.parse(t):{};throw new e(s,o.status,o.headers)}const u=[204,205,304].includes(o.status)?null:await o.text();return{body:u?JSON.parse(u):{},status:o.status,headers:o.headers}},verifyToken:async(s,a)=>{const r=`${t}/token/verify`,i=await n(r,{...a,method:"POST",headers:{"Content-Type":"application/json",...a?.headers},body:JSON.stringify(s)});if(i.status>=300){const t=[412].includes(i.status)?null:await i.text(),s=t?JSON.parse(t):{};throw new e(s,i.status,i.headers)}const o=[204,205,304].includes(i.status)?null:await i.text();return{body:o?JSON.parse(o):{},status:i.status,headers:i.headers}},getUser:async s=>{const a=`${t}/user`,r=await n(a,{...s,method:"GET",headers:{...s?.headers}});if(r.status>=300){const t=[412].includes(r.status)?null:await r.text(),s=t?JSON.parse(t):{};throw new e(s,r.status,r.headers)}const i=[204,205,304].includes(r.status)?null:await r.text();return{body:i?JSON.parse(i):{},status:r.status,headers:r.headers}},deanonymizeUser:async(s,a)=>{const r=`${t}/user/deanonymize`,i=await n(r,{...a,method:"POST",headers:{"Content-Type":"application/json",...a?.headers},body:JSON.stringify(s)});if(i.status>=300){const t=[412].includes(i.status)?null:await i.text(),s=t?JSON.parse(t):{};throw new e(s,i.status,i.headers)}const o=[204,205,304].includes(i.status)?null:await i.text();return{body:o?JSON.parse(o):{},status:i.status,headers:i.headers}},changeUserEmail:async(s,a)=>{const r=`${t}/user/email/change`,i=await n(r,{...a,method:"POST",headers:{"Content-Type":"application/json",...a?.headers},body:JSON.stringify(s)});if(i.status>=300){const t=[412].includes(i.status)?null:await i.text(),s=t?JSON.parse(t):{};throw new e(s,i.status,i.headers)}const o=[204,205,304].includes(i.status)?null:await i.text();return{body:o?JSON.parse(o):{},status:i.status,headers:i.headers}},sendVerificationEmail:async(s,a)=>{const r=`${t}/user/email/send-verification-email`,i=await n(r,{...a,method:"POST",headers:{"Content-Type":"application/json",...a?.headers},body:JSON.stringify(s)});if(i.status>=300){const t=[412].includes(i.status)?null:await i.text(),s=t?JSON.parse(t):{};throw new e(s,i.status,i.headers)}const o=[204,205,304].includes(i.status)?null:await i.text();return{body:o?JSON.parse(o):{},status:i.status,headers:i.headers}},verifyChangeUserMfa:async(s,a)=>{const r=`${t}/user/mfa`,i=await n(r,{...a,method:"POST",headers:{"Content-Type":"application/json",...a?.headers},body:JSON.stringify(s)});if(i.status>=300){const t=[412].includes(i.status)?null:await i.text(),s=t?JSON.parse(t):{};throw new e(s,i.status,i.headers)}const o=[204,205,304].includes(i.status)?null:await i.text();return{body:o?JSON.parse(o):{},status:i.status,headers:i.headers}},changeUserPassword:async(s,a)=>{const r=`${t}/user/password`,i=await n(r,{...a,method:"POST",headers:{"Content-Type":"application/json",...a?.headers},body:JSON.stringify(s)});if(i.status>=300){const t=[412].includes(i.status)?null:await i.text(),s=t?JSON.parse(t):{};throw new e(s,i.status,i.headers)}const o=[204,205,304].includes(i.status)?null:await i.text();return{body:o?JSON.parse(o):{},status:i.status,headers:i.headers}},sendPasswordResetEmail:async(s,a)=>{const r=`${t}/user/password/reset`,i=await n(r,{...a,method:"POST",headers:{"Content-Type":"application/json",...a?.headers},body:JSON.stringify(s)});if(i.status>=300){const t=[412].includes(i.status)?null:await i.text(),s=t?JSON.parse(t):{};throw new e(s,i.status,i.headers)}const o=[204,205,304].includes(i.status)?null:await i.text();return{body:o?JSON.parse(o):{},status:i.status,headers:i.headers}},addSecurityKey:async s=>{const a=`${t}/user/webauthn/add`,r=await n(a,{...s,method:"POST",headers:{...s?.headers}});if(r.status>=300){const t=[412].includes(r.status)?null:await r.text(),s=t?JSON.parse(t):{};throw new e(s,r.status,r.headers)}const i=[204,205,304].includes(r.status)?null:await r.text();return{body:i?JSON.parse(i):{},status:r.status,headers:r.headers}},verifyAddSecurityKey:async(s,a)=>{const r=`${t}/user/webauthn/verify`,i=await n(r,{...a,method:"POST",headers:{"Content-Type":"application/json",...a?.headers},body:JSON.stringify(s)});if(i.status>=300){const t=[412].includes(i.status)?null:await i.text(),s=t?JSON.parse(t):{};throw new e(s,i.status,i.headers)}const o=[204,205,304].includes(i.status)?null:await i.text();return{body:o?JSON.parse(o):{},status:i.status,headers:i.headers}},verifyTicketURL:s=>{const e=s&&Object.entries(s).flatMap((([t,s])=>{const e=Array.isArray(s)?s.join(","):"object"==typeof s&&null!==s?JSON.stringify(s):String(s);return[`${t}=${encodeURIComponent(e)}`]})).join("&");return e?`${t}/verify?${e}`:`${t}/verify`},getVersion:async s=>{const a=`${t}/version`,r=await n(a,{...s,method:"GET",headers:{...s?.headers}});if(r.status>=300){const t=[412].includes(r.status)?null:await r.text(),s=t?JSON.parse(t):{};throw new e(s,r.status,r.headers)}const i=[204,205,304].includes(r.status)?null:await r.text();return{body:i?JSON.parse(i):{},status:r.status,headers:r.headers}}}})(l),O=((t,a=[])=>{let n=s(a);return{baseURL:t,pushChainFunction:t=>{a.push(t),n=s(a)},uploadFiles:async(s,a)=>{const r=`${t}/files`,i=new FormData,o="undefined"!=typeof navigator&&"ReactNative"===navigator.product;void 0!==s["bucket-id"]&&i.append("bucket-id",s["bucket-id"]),void 0!==s["metadata[]"]&&s["metadata[]"].forEach((t=>{o?i.append("metadata[]",{string:JSON.stringify(t),type:"application/json",name:""}):i.append("metadata[]",new Blob([JSON.stringify(t)],{type:"application/json"}),"")})),void 0!==s["file[]"]&&s["file[]"].forEach((t=>{i.append("file[]",t)}));const u=await n(r,{...a,method:"POST",body:i});if(u.status>=300){const t=[412].includes(u.status)?null:await u.text(),s=t?JSON.parse(t):{};throw new e(s,u.status,u.headers)}const d=[204,205,304].includes(u.status)?null:await u.text();return{body:d?JSON.parse(d):{},status:u.status,headers:u.headers}},deleteFile:async(s,a)=>{const r=`${t}/files/${s}`,i=await n(r,{...a,method:"DELETE",headers:{...a?.headers}});if(i.status>=300){const t=[412].includes(i.status)?null:await i.text(),s=t?JSON.parse(t):{};throw new e(s,i.status,i.headers)}return{body:void 0,status:i.status,headers:i.headers}},getFile:async(s,a,r)=>{const i=a&&Object.entries(a).flatMap((([t,s])=>{const e=Array.isArray(s)?s.join(","):"object"==typeof s&&null!==s?JSON.stringify(s):String(s);return[`${t}=${encodeURIComponent(e)}`]})).join("&"),o=i?`${t}/files/${s}?${i}`:`${t}/files/${s}`,u=await n(o,{...r,method:"GET",headers:{...r?.headers}});if(u.status>=300){const t=[412].includes(u.status)?null:await u.text(),s=t?JSON.parse(t):{};throw new e(s,u.status,u.headers)}return{body:await u.blob(),status:u.status,headers:u.headers}},getFileMetadataHeaders:async(s,a,r)=>{const i=a&&Object.entries(a).flatMap((([t,s])=>{const e=Array.isArray(s)?s.join(","):"object"==typeof s&&null!==s?JSON.stringify(s):String(s);return[`${t}=${encodeURIComponent(e)}`]})).join("&"),o=i?`${t}/files/${s}?${i}`:`${t}/files/${s}`,u=await n(o,{...r,method:"HEAD",headers:{...r?.headers}});if(u.status>=300){const t=[412].includes(u.status)?null:await u.text(),s=t?JSON.parse(t):{};throw new e(s,u.status,u.headers)}return{body:void 0,status:u.status,headers:u.headers}},replaceFile:async(s,a,r)=>{const i=`${t}/files/${s}`,o=new FormData,u="undefined"!=typeof navigator&&"ReactNative"===navigator.product;void 0!==a.metadata&&(u?o.append("metadata",{string:JSON.stringify(a.metadata),type:"application/json",name:""}):o.append("metadata",new Blob([JSON.stringify(a.metadata)],{type:"application/json"}),"")),void 0!==a.file&&o.append("file",a.file);const d=await n(i,{...r,method:"PUT",body:o});if(d.status>=300){const t=[412].includes(d.status)?null:await d.text(),s=t?JSON.parse(t):{};throw new e(s,d.status,d.headers)}const c=[204,205,304].includes(d.status)?null:await d.text();return{body:c?JSON.parse(c):{},status:d.status,headers:d.headers}},getFilePresignedURL:async(s,a)=>{const r=`${t}/files/${s}/presignedurl`,i=await n(r,{...a,method:"GET",headers:{...a?.headers}});if(i.status>=300){const t=[412].includes(i.status)?null:await i.text(),s=t?JSON.parse(t):{};throw new e(s,i.status,i.headers)}const o=[204,205,304].includes(i.status)?null:await i.text();return{body:o?JSON.parse(o):{},status:i.status,headers:i.headers}},deleteBrokenMetadata:async s=>{const a=`${t}/ops/delete-broken-metadata`,r=await n(a,{...s,method:"POST",headers:{...s?.headers}});if(r.status>=300){const t=[412].includes(r.status)?null:await r.text(),s=t?JSON.parse(t):{};throw new e(s,r.status,r.headers)}const i=[204,205,304].includes(r.status)?null:await r.text();return{body:i?JSON.parse(i):{},status:r.status,headers:r.headers}},deleteOrphanedFiles:async s=>{const a=`${t}/ops/delete-orphans`,r=await n(a,{...s,method:"POST",headers:{...s?.headers}});if(r.status>=300){const t=[412].includes(r.status)?null:await r.text(),s=t?JSON.parse(t):{};throw new e(s,r.status,r.headers)}const i=[204,205,304].includes(r.status)?null:await r.text();return{body:i?JSON.parse(i):{},status:r.status,headers:r.headers}},listBrokenMetadata:async s=>{const a=`${t}/ops/list-broken-metadata`,r=await n(a,{...s,method:"POST",headers:{...s?.headers}});if(r.status>=300){const t=[412].includes(r.status)?null:await r.text(),s=t?JSON.parse(t):{};throw new e(s,r.status,r.headers)}const i=[204,205,304].includes(r.status)?null:await r.text();return{body:i?JSON.parse(i):{},status:r.status,headers:r.headers}},listFilesNotUploaded:async s=>{const a=`${t}/ops/list-not-uploaded`,r=await n(a,{...s,method:"POST",headers:{...s?.headers}});if(r.status>=300){const t=[412].includes(r.status)?null:await r.text(),s=t?JSON.parse(t):{};throw new e(s,r.status,r.headers)}const i=[204,205,304].includes(r.status)?null:await r.text();return{body:i?JSON.parse(i):{},status:r.status,headers:r.headers}},listOrphanedFiles:async s=>{const a=`${t}/ops/list-orphans`,r=await n(a,{...s,method:"POST",headers:{...s?.headers}});if(r.status>=300){const t=[412].includes(r.status)?null:await r.text(),s=t?JSON.parse(t):{};throw new e(s,r.status,r.headers)}const i=[204,205,304].includes(r.status)?null:await r.text();return{body:i?JSON.parse(i):{},status:r.status,headers:r.headers}},getVersion:async s=>{const a=`${t}/version`,r=await n(a,{...s,method:"GET",headers:{...s?.headers}});if(r.status>=300){const t=[412].includes(r.status)?null:await r.text(),s=t?JSON.parse(t):{};throw new e(s,r.status,r.headers)}const i=[204,205,304].includes(r.status)?null:await r.text();return{body:i?JSON.parse(i):{},status:r.status,headers:r.headers}}}})(p,[]),m=((t,a=[])=>{let n=s(a);const r=async(s,a)=>{const r=await n(`${t}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s),...a}),i=await r.text(),o=i?JSON.parse(i):{},u={body:o,status:r.status,headers:r.headers};if(o.errors)throw new e(o,r.status,r.headers);return u};return{request:function(t,s,e){if("object"==typeof t&&"kind"in t){const a=t.definitions[0],n={query:t.loc?.source.body||"",variables:s,operationName:a&&"name"in a?a.name?.value:void 0};return r(n,e)}return r(t,s)},url:t,pushChainFunction:t=>{a.push(t),n=s(a)}}})(w,[]),J=((t,a=[])=>{let n=s(a);const r=async(s,a)=>{const r=await n(`${t}${s}`,a);let i;if(i=r.headers.get("content-type")?.includes("application/json")?await r.json():r.headers.get("content-type")?.startsWith("text/")?await r.text():await r.blob(),!r.ok)throw new e(i,r.status,r.headers);return{status:r.status,body:i,headers:r.headers}};return{baseURL:t,fetch:r,post:async(t,s,e={})=>{const a={...e,method:"POST",headers:{Accept:"application/json","Content-Type":"application/json",...e.headers},body:s?JSON.stringify(s):void 0};return r(t,a)},pushChainFunction:t=>{a.push(t),n=s(a)}}})(y,[]);for(const s of c)s({auth:g,storage:O,graphql:m,functions:J,sessionStorage:h});return new b(g,O,m,J,h)}const N=(t,s,e,a)=>a||(s&&e?`https://${s}.${t}.${e}.nhost.run/v1`:`https://local.${t}.local.nhost.run/v1`);t.createClient=function(t={}){const s=t.storage??S();return m({...t,storage:s,configure:[g,...t.configure??[]]})},t.createNhostClient=m,t.createServerClient=function(t){return m({...t,configure:[O,...t.configure??[]]})},t.generateServiceUrl=N,t.withAdminSession=function(t){return({storage:s,graphql:e,functions:a})=>{const n=(r=t,t=>async(s,e={})=>{const a=new Headers(e.headers||{});if(a.has("x-hasura-admin-secret")||a.set("x-hasura-admin-secret",r.adminSecret),r.role&&!a.has("x-hasura-role")&&a.set("x-hasura-role",r.role),r.sessionVariables)for(const[t,n]of Object.entries(r.sessionVariables)){const s=t.startsWith("x-hasura-")?t:`x-hasura-${t}`;a.has(s)||a.set(s,n)}return t(s,{...e,headers:a})});var r;s.pushChainFunction(n),e.pushChainFunction(n),a.pushChainFunction(n)}},t.withClientSideSessionMiddleware=g,t.withServerSideSessionMiddleware=O,Object.defineProperty(t,Symbol.toStringTag,{value:"Module"})}));
2
2
  //# sourceMappingURL=nhost-js.umd.js.map