een-api-toolkit 0.3.16 → 0.3.20

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.
Files changed (30) hide show
  1. package/CHANGELOG.md +43 -10
  2. package/README.md +1 -0
  3. package/dist/index.cjs +3 -1
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.d.ts +561 -0
  6. package/dist/index.js +483 -260
  7. package/dist/index.js.map +1 -1
  8. package/docs/AI-CONTEXT.md +12 -1
  9. package/examples/vue-event-subscriptions/.env.example +15 -0
  10. package/examples/vue-event-subscriptions/README.md +103 -0
  11. package/examples/vue-event-subscriptions/e2e/app.spec.ts +71 -0
  12. package/examples/vue-event-subscriptions/e2e/auth.spec.ts +290 -0
  13. package/examples/vue-event-subscriptions/index.html +13 -0
  14. package/examples/vue-event-subscriptions/package-lock.json +1719 -0
  15. package/examples/vue-event-subscriptions/package.json +28 -0
  16. package/examples/vue-event-subscriptions/playwright.config.ts +47 -0
  17. package/examples/vue-event-subscriptions/src/App.vue +233 -0
  18. package/examples/vue-event-subscriptions/src/main.ts +25 -0
  19. package/examples/vue-event-subscriptions/src/router/index.ts +68 -0
  20. package/examples/vue-event-subscriptions/src/views/Callback.vue +76 -0
  21. package/examples/vue-event-subscriptions/src/views/Home.vue +192 -0
  22. package/examples/vue-event-subscriptions/src/views/LiveEvents.vue +640 -0
  23. package/examples/vue-event-subscriptions/src/views/Login.vue +33 -0
  24. package/examples/vue-event-subscriptions/src/views/Logout.vue +59 -0
  25. package/examples/vue-event-subscriptions/src/views/Subscriptions.vue +402 -0
  26. package/examples/vue-event-subscriptions/src/vite-env.d.ts +12 -0
  27. package/examples/vue-event-subscriptions/tsconfig.json +21 -0
  28. package/examples/vue-event-subscriptions/tsconfig.node.json +10 -0
  29. package/examples/vue-event-subscriptions/vite.config.ts +12 -0
  30. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../src/utils/debug.ts","../src/utils/storage.ts","../src/config.ts","../src/types/common.ts","../src/utils/timestamp.ts","../src/auth/store.ts","../src/auth/service.ts","../src/users/service.ts","../src/cameras/service.ts","../src/bridges/service.ts","../src/media/service.ts","../src/feeds/service.ts","../src/events/service.ts","../src/eventMetrics/service.ts","../src/alerts/service.ts","../src/notifications/service.ts"],"sourcesContent":["/**\n * Debug logging utility\n * Enabled when VITE_DEBUG=true in environment\n */\n\nconst isDebugEnabled = (): boolean => {\n try {\n return import.meta.env?.VITE_DEBUG === 'true'\n } catch {\n return false\n }\n}\n\nexport function debug(...args: unknown[]): void {\n if (isDebugEnabled()) {\n console.log('[een-api-toolkit]', ...args)\n }\n}\n\nexport function debugWarn(...args: unknown[]): void {\n if (isDebugEnabled()) {\n console.warn('[een-api-toolkit]', ...args)\n }\n}\n\nexport function debugError(...args: unknown[]): void {\n if (isDebugEnabled()) {\n console.error('[een-api-toolkit]', ...args)\n }\n}\n","// Import StorageStrategy from types to maintain single source of truth\nimport type { StorageStrategy } from '../types'\nimport { debug } from './debug'\n\n// Re-export for convenience\nexport type { StorageStrategy }\n\n/**\n * Human-readable descriptions for each storage strategy.\n * Useful for displaying storage information in UI components.\n *\n * @example\n * ```typescript\n * import { getStorageStrategy, STORAGE_STRATEGY_DESCRIPTIONS } from 'een-api-toolkit'\n *\n * const strategy = getStorageStrategy()\n * const description = STORAGE_STRATEGY_DESCRIPTIONS[strategy]\n * console.log(`Using ${strategy}: ${description}`)\n * ```\n *\n * @category Configuration\n */\nexport const STORAGE_STRATEGY_DESCRIPTIONS: Record<StorageStrategy, string> = {\n localStorage: 'persists across sessions',\n sessionStorage: 'per-tab, cleared on tab close',\n memory: 'tokens lost on page refresh'\n}\n\n/**\n * Storage adapter interface for token persistence.\n * @internal\n */\nexport interface StorageAdapter {\n getItem(key: string): string | null\n setItem(key: string, value: string): void\n removeItem(key: string): void\n}\n\n/**\n * In-memory storage implementation.\n * Tokens are lost on page refresh but are immune to storage-based XSS attacks.\n * @internal\n */\nclass MemoryStorage implements StorageAdapter {\n private store = new Map<string, string>()\n\n getItem(key: string): string | null {\n return this.store.get(key) ?? null\n }\n\n setItem(key: string, value: string): void {\n this.store.set(key, value)\n }\n\n removeItem(key: string): void {\n this.store.delete(key)\n }\n}\n\n/**\n * Browser storage wrapper that delegates to localStorage/sessionStorage.\n * Errors are propagated to the caller (auth/store.ts) for proper logging.\n * @internal\n */\nclass BrowserStorageAdapter implements StorageAdapter {\n constructor(private storage: Storage) {}\n\n getItem(key: string): string | null {\n return this.storage.getItem(key)\n }\n\n setItem(key: string, value: string): void {\n this.storage.setItem(key, value)\n }\n\n removeItem(key: string): void {\n this.storage.removeItem(key)\n }\n}\n\n// Singleton instances\nlet currentStrategy: StorageStrategy = 'localStorage'\nlet memoryStorageInstance: MemoryStorage | null = null\n\n/**\n * Get the memory storage singleton instance.\n * @internal\n */\nfunction getMemoryStorage(): MemoryStorage {\n if (!memoryStorageInstance) {\n memoryStorageInstance = new MemoryStorage()\n }\n return memoryStorageInstance\n}\n\n/**\n * Set the storage strategy for the toolkit.\n *\n * @param strategy - The storage strategy to use\n *\n * @remarks\n * This should be called during toolkit initialization via {@link initEenToolkit}.\n * Changing the strategy after authentication may cause the current session to be lost.\n *\n * @internal\n */\nexport function setStorageStrategy(strategy: StorageStrategy): void {\n currentStrategy = strategy\n}\n\n/**\n * Get the current storage strategy.\n *\n * @returns The currently configured storage strategy\n *\n * @category Configuration\n */\nexport function getStorageStrategy(): StorageStrategy {\n return currentStrategy\n}\n\n/**\n * Get the storage adapter for the current strategy.\n *\n * @returns A storage adapter implementation based on the configured strategy\n *\n * @internal\n */\nexport function getStorageAdapter(): StorageAdapter {\n switch (currentStrategy) {\n case 'memory':\n return getMemoryStorage()\n case 'sessionStorage':\n if (typeof sessionStorage !== 'undefined') {\n return new BrowserStorageAdapter(sessionStorage)\n }\n // Fallback to memory if sessionStorage not available\n debug('sessionStorage unavailable, falling back to memory storage')\n return getMemoryStorage()\n case 'localStorage':\n default:\n if (typeof localStorage !== 'undefined') {\n return new BrowserStorageAdapter(localStorage)\n }\n // Fallback to memory if localStorage not available\n debug('localStorage unavailable, falling back to memory storage')\n return getMemoryStorage()\n }\n}\n\n/**\n * Clear the memory storage instance.\n * Useful for testing or when switching strategies.\n *\n * @internal\n */\nexport function clearMemoryStorage(): void {\n memoryStorageInstance = null\n}\n","import type { EenToolkitConfig, StorageStrategy } from './types'\nimport { setStorageStrategy, getStorageStrategy, STORAGE_STRATEGY_DESCRIPTIONS } from './utils/storage'\n\n/**\n * Global toolkit configuration\n */\nlet config: EenToolkitConfig = {}\n\n/**\n * Initialize the EEN API Toolkit\n *\n * @remarks\n * Call this function once at application startup before using any toolkit features.\n * The storage strategy determines how authentication tokens are persisted.\n *\n * @param options - Configuration options for the toolkit\n *\n * @example\n * ```typescript\n * import { initEenToolkit } from 'een-api-toolkit'\n *\n * // Basic initialization with localStorage (default, backwards compatible)\n * initEenToolkit({\n * proxyUrl: 'https://your-proxy.workers.dev',\n * clientId: 'your-client-id'\n * })\n *\n * // High-security initialization with memory-only storage\n * initEenToolkit({\n * proxyUrl: 'https://your-proxy.workers.dev',\n * clientId: 'your-client-id',\n * storageStrategy: 'memory'\n * })\n * ```\n */\nexport function initEenToolkit(options: EenToolkitConfig = {}): void {\n // Set storage strategy first (default to localStorage for backwards compatibility)\n const storageStrategy: StorageStrategy = options.storageStrategy ?? 'localStorage'\n setStorageStrategy(storageStrategy)\n\n config = {\n proxyUrl: options.proxyUrl ?? import.meta.env?.VITE_PROXY_URL,\n clientId: options.clientId ?? import.meta.env?.VITE_EEN_CLIENT_ID,\n redirectUri: options.redirectUri ?? import.meta.env?.VITE_REDIRECT_URI,\n storageStrategy,\n debug: options.debug ?? import.meta.env?.VITE_DEBUG === 'true'\n }\n}\n\nexport { getStorageStrategy, STORAGE_STRATEGY_DESCRIPTIONS }\n\n/**\n * Get the current configuration\n */\nexport function getConfig(): EenToolkitConfig {\n return config\n}\n\n/**\n * Get the proxy URL\n */\nexport function getProxyUrl(): string | undefined {\n return config.proxyUrl ?? import.meta.env?.VITE_PROXY_URL\n}\n\n/**\n * Get the client ID\n */\nexport function getClientId(): string | undefined {\n return config.clientId ?? import.meta.env?.VITE_EEN_CLIENT_ID\n}\n\n/**\n * Get the redirect URI\n */\nexport function getRedirectUri(): string {\n return config.redirectUri ?? import.meta.env?.VITE_REDIRECT_URI ?? 'http://127.0.0.1:3333'\n}\n","/**\n * Error codes returned by the toolkit.\n *\n * @remarks\n * All API functions return a {@link Result} type that contains either data or an error.\n * The error code helps you determine how to handle the failure.\n *\n * @category Types\n */\nexport type ErrorCode =\n | 'AUTH_REQUIRED'\n | 'AUTH_FAILED'\n | 'TOKEN_EXPIRED'\n | 'API_ERROR'\n | 'NETWORK_ERROR'\n | 'VALIDATION_ERROR'\n | 'NOT_FOUND'\n | 'FORBIDDEN'\n | 'RATE_LIMITED'\n | 'SERVICE_UNAVAILABLE'\n | 'UNKNOWN_ERROR'\n\n/**\n * Error object returned when an operation fails.\n *\n * @remarks\n * Contains structured error information including a machine-readable code,\n * human-readable message, and optional HTTP status code.\n *\n * @example\n * ```typescript\n * const { error } = await getUsers()\n * if (error) {\n * console.error(`${error.code}: ${error.message}`)\n * if (error.status === 401) {\n * redirectToLogin()\n * }\n * }\n * ```\n *\n * @category Types\n */\nexport interface EenError {\n /** Machine-readable error code for programmatic handling */\n code: ErrorCode\n /** Human-readable error message */\n message: string\n /** HTTP status code if the error came from an API response */\n status?: number\n /** Additional error details (varies by error type) */\n details?: unknown\n}\n\n/**\n * Result type for all API operations - functions never throw exceptions.\n *\n * @remarks\n * This is a discriminated union type. When `error` is `null`, `data` contains\n * the successful result. When `error` is not `null`, `data` is `null`.\n * TypeScript will narrow the type correctly after checking for errors.\n *\n * @example\n * ```typescript\n * const { data, error } = await getUsers()\n *\n * if (error) {\n * // TypeScript knows: data is null, error is EenError\n * console.error(error.message)\n * return\n * }\n *\n * // TypeScript knows: data is not null, error is null\n * console.log(data.results)\n * ```\n *\n * @typeParam T - The type of the data on success\n * @category Types\n */\nexport type Result<T> =\n | { data: T; error: null }\n | { data: null; error: EenError }\n\n/**\n * Pagination parameters for list operations.\n *\n * @remarks\n * Most list APIs in the EEN platform support pagination. Use `pageSize` to\n * control how many results are returned, and `pageToken` to fetch subsequent pages.\n *\n * @example\n * ```typescript\n * // First page\n * const { data } = await getUsers({ pageSize: 50 })\n *\n * // Next page (if available)\n * if (data.nextPageToken) {\n * const { data: page2 } = await getUsers({\n * pageSize: 50,\n * pageToken: data.nextPageToken\n * })\n * }\n * ```\n *\n * @category Types\n */\nexport interface PaginationParams {\n /** Number of results per page (default varies by endpoint, typically 100) */\n pageSize?: number\n /** Token for fetching a specific page (from previous response's nextPageToken) */\n pageToken?: string\n}\n\n/**\n * Paginated response from list operations.\n *\n * @remarks\n * Contains the results array and optional pagination tokens for navigating\n * through large result sets.\n *\n * @typeParam T - The type of items in the results array\n * @category Types\n */\nexport interface PaginatedResult<T> {\n /** Array of items for this page */\n results: T[]\n /** Token to fetch the next page (undefined if no more pages) */\n nextPageToken?: string\n /** Token to fetch the previous page (undefined if on first page) */\n prevPageToken?: string\n /** Total number of items across all pages (may not be provided by all endpoints) */\n totalSize?: number\n}\n\n/**\n * Storage strategy options for token persistence.\n *\n * @remarks\n * Different storage strategies offer different security/convenience tradeoffs:\n *\n * - **localStorage**: Tokens persist across browser sessions. Most convenient but\n * vulnerable to XSS attacks since JavaScript can access localStorage.\n *\n * - **sessionStorage**: Tokens persist within a single tab session. Cleared when\n * the tab is closed. Each tab has isolated storage, so opening a new tab\n * requires re-authentication.\n *\n * - **memory**: Tokens are only kept in memory (Pinia store). Most secure as\n * tokens are never written to disk, but any page refresh requires re-authentication.\n *\n * @category Configuration\n */\nexport type StorageStrategy = 'localStorage' | 'sessionStorage' | 'memory'\n\n/**\n * Configuration for initializing the toolkit.\n *\n * @remarks\n * Pass this to {@link initEenToolkit} to configure the library. All options\n * can also be set via environment variables (VITE_PROXY_URL, VITE_EEN_CLIENT_ID,\n * VITE_REDIRECT_URI, VITE_DEBUG).\n *\n * @example\n * ```typescript\n * import { initEenToolkit } from 'een-api-toolkit'\n *\n * initEenToolkit({\n * proxyUrl: 'https://your-proxy.workers.dev',\n * clientId: 'your-een-client-id',\n * redirectUri: 'http://localhost:5173/callback',\n * storageStrategy: 'sessionStorage', // More secure than default\n * debug: true\n * })\n * ```\n *\n * @category Configuration\n */\nexport interface EenToolkitConfig {\n /** URL of the OAuth proxy server (required for API calls) */\n proxyUrl?: string\n /** EEN OAuth client ID (required for authentication) */\n clientId?: string\n /** OAuth redirect URI (default: http://127.0.0.1:3333) */\n redirectUri?: string\n /**\n * Storage strategy for token persistence (default: 'localStorage').\n *\n * Security vs convenience tradeoffs:\n * - 'localStorage': Persists across sessions, vulnerable to XSS\n * - 'sessionStorage': Per-tab isolation, cleared on tab close\n * - 'memory': Most secure, lost on page refresh\n */\n storageStrategy?: StorageStrategy\n /** Enable debug logging to console */\n debug?: boolean\n}\n\n/**\n * Helper to create a success result.\n *\n * @param data - The successful result data\n * @returns A Result object with data and null error\n *\n * @internal\n */\nexport function success<T>(data: T): Result<T> {\n return { data, error: null }\n}\n\n/**\n * Helper to create an error result.\n *\n * @param code - The error code\n * @param message - Human-readable error message\n * @param status - Optional HTTP status code\n * @param details - Optional additional error details\n * @returns A Result object with null data and error\n *\n * @internal\n */\nexport function failure<T>(code: ErrorCode, message: string, status?: number, details?: unknown): Result<T> {\n return { data: null, error: { code, message, status, details } }\n}\n","/**\n * Convert ISO 8601 timestamp from Z format to +00:00 format.\n *\n * @remarks\n * The EEN API requires timestamps in +00:00 format, not Z format.\n * This function converts timestamps like `2024-01-01T00:00:00.000Z`\n * to `2024-01-01T00:00:00.000+00:00`.\n *\n * @param timestamp - ISO 8601 timestamp string\n * @returns Timestamp in +00:00 format\n *\n * @example\n * ```typescript\n * formatTimestamp('2024-01-01T00:00:00.000Z')\n * // Returns: '2024-01-01T00:00:00.000+00:00'\n *\n * formatTimestamp(new Date().toISOString())\n * // Returns: timestamp with +00:00 suffix\n * ```\n *\n * @category Utilities\n */\nexport function formatTimestamp(timestamp: string): string {\n // If already in +00:00 format, return as-is\n if (timestamp.endsWith('+00:00')) {\n return timestamp\n }\n // Convert Z to +00:00\n if (timestamp.endsWith('Z')) {\n return timestamp.replace('Z', '+00:00')\n }\n // Return original if format is not recognized\n return timestamp\n}\n","import { defineStore } from 'pinia'\nimport { ref, computed } from 'vue'\nimport type { UserProfile } from '../types'\nimport type { Result } from '../types'\nimport { debug } from '../utils/debug'\nimport { getStorageAdapter } from '../utils/storage'\n\n// Lazy-loaded reference to refreshToken to avoid circular dependency at import time\n// Caches the promise (not the resolved value) to prevent race conditions with concurrent calls\nlet refreshTokenFnPromise: Promise<() => Promise<Result<{ accessToken: string; expiresIn: number }>>> | null = null\n\nfunction getRefreshTokenFn() {\n if (!refreshTokenFnPromise) {\n refreshTokenFnPromise = import('./service').then((service) => service.refreshToken)\n }\n return refreshTokenFnPromise\n}\n\n/**\n * Pinia store for authentication state management\n */\nexport const useAuthStore = defineStore('een-auth', () => {\n // State\n const token = ref<string | null>(null)\n const tokenExpiration = ref<number | null>(null)\n const refreshTokenMarker = ref<string | null>(null)\n const sessionId = ref<string | null>(null)\n const hostname = ref<string | null>(null)\n const port = ref<number>(443)\n const userProfile = ref<UserProfile | null>(null)\n const refreshTimerId = ref<ReturnType<typeof setTimeout> | null>(null)\n const isRefreshing = ref(false)\n let refreshPromise: Promise<void> | null = null\n const refreshFailed = ref(false)\n const refreshFailedMessage = ref<string | null>(null)\n\n // Computed\n const isAuthenticated = computed(() => !!token.value)\n\n const baseUrl = computed(() => {\n if (!hostname.value) return null\n return port.value === 443\n ? `https://${hostname.value}`\n : `https://${hostname.value}:${port.value}`\n })\n\n const isTokenExpired = computed(() => {\n if (!tokenExpiration.value) return true\n return Date.now() >= tokenExpiration.value\n })\n\n const tokenExpiresIn = computed(() => {\n if (!tokenExpiration.value) return 0\n return Math.max(0, tokenExpiration.value - Date.now())\n })\n\n // Actions\n function setToken(newToken: string, expiresIn: number) {\n token.value = newToken\n tokenExpiration.value = Date.now() + expiresIn * 1000\n saveToStorage()\n setupAutoRefresh()\n debug('Token set, expires in', expiresIn, 'seconds')\n }\n\n function setRefreshTokenMarker(marker: string) {\n refreshTokenMarker.value = marker\n saveToStorage()\n }\n\n function setSessionId(newSessionId: string) {\n sessionId.value = newSessionId\n saveToStorage()\n }\n\n function setBaseUrl(data: string | { hostname: string; port?: number }) {\n if (typeof data === 'string') {\n // Parse URL string\n try {\n const url = new URL(data.startsWith('http') ? data : `https://${data}`)\n hostname.value = url.hostname\n port.value = url.port ? parseInt(url.port, 10) : 443\n } catch (err: unknown) {\n // Invalid URL format, use as hostname directly\n debug('Failed to parse URL, using as hostname:', err instanceof Error ? err.message : String(err))\n hostname.value = data\n port.value = 443\n }\n } else {\n hostname.value = data.hostname\n port.value = data.port ?? 443\n }\n saveToStorage()\n debug('Base URL set:', baseUrl.value)\n }\n\n function setUserProfile(profile: UserProfile) {\n userProfile.value = profile\n saveToStorage()\n }\n\n function setupAutoRefresh() {\n // Clear existing timer\n if (refreshTimerId.value) {\n clearTimeout(refreshTimerId.value)\n refreshTimerId.value = null\n }\n\n if (!tokenExpiration.value || !token.value) {\n return\n }\n\n const now = Date.now()\n const expiresAt = tokenExpiration.value\n const timeUntilExpiry = expiresAt - now\n\n // Calculate refresh time: 5 minutes before expiration or 50% of TTL, whichever is earlier\n // Minimum: 1 minute before expiration, minimum timeout: 5 seconds\n const fiveMinutes = 5 * 60 * 1000\n const halfTtl = timeUntilExpiry / 2\n const refreshBuffer = Math.min(fiveMinutes, halfTtl)\n const refreshTime = Math.max(timeUntilExpiry - refreshBuffer, 60 * 1000)\n const timeout = Math.max(refreshTime, 5000)\n\n debug('Auto-refresh scheduled in', Math.round(timeout / 1000), 'seconds')\n\n refreshTimerId.value = setTimeout(async () => {\n await performAutoRefresh()\n }, timeout)\n }\n\n async function performAutoRefresh(): Promise<void> {\n // If refresh is already in progress, wait for the existing promise\n if (refreshPromise) {\n debug('Refresh already in progress, waiting for existing refresh')\n return refreshPromise\n }\n\n isRefreshing.value = true\n debug('Performing auto-refresh')\n\n refreshPromise = (async () => {\n try {\n const refreshToken = await getRefreshTokenFn()\n const result = await refreshToken()\n\n if (result.error) {\n refreshFailed.value = true\n refreshFailedMessage.value = result.error.message\n debug('Auto-refresh failed:', result.error.message)\n } else {\n refreshFailed.value = false\n refreshFailedMessage.value = null\n debug('Auto-refresh successful')\n }\n } catch (err: unknown) {\n refreshFailed.value = true\n refreshFailedMessage.value = err instanceof Error ? err.message : String(err)\n debug('Auto-refresh error:', err)\n } finally {\n isRefreshing.value = false\n refreshPromise = null\n }\n })()\n\n return refreshPromise\n }\n\n function clearRefreshFailed() {\n refreshFailed.value = false\n refreshFailedMessage.value = null\n }\n\n function logout() {\n // Clear timer\n if (refreshTimerId.value) {\n clearTimeout(refreshTimerId.value)\n refreshTimerId.value = null\n }\n\n // Clear state\n token.value = null\n tokenExpiration.value = null\n refreshTokenMarker.value = null\n sessionId.value = null\n hostname.value = null\n port.value = 443\n userProfile.value = null\n refreshFailed.value = false\n refreshFailedMessage.value = null\n\n // Clear storage\n clearStorage()\n debug('Logged out')\n }\n\n function initialize() {\n loadFromStorage()\n if (token.value && !isTokenExpired.value) {\n setupAutoRefresh()\n debug('Initialized from storage')\n } else if (token.value && isTokenExpired.value) {\n debug('Stored token expired, clearing')\n logout()\n }\n }\n\n // Storage helpers - use configured storage strategy\n function saveToStorage() {\n try {\n const storage = getStorageAdapter()\n if (token.value) storage.setItem('een_token', token.value)\n if (tokenExpiration.value) storage.setItem('een_tokenExpiration', String(tokenExpiration.value))\n if (refreshTokenMarker.value) storage.setItem('een_refreshTokenMarker', refreshTokenMarker.value)\n if (sessionId.value) storage.setItem('een_sessionId', sessionId.value)\n if (hostname.value) storage.setItem('een_hostname', hostname.value)\n if (port.value !== 443) storage.setItem('een_port', String(port.value))\n if (userProfile.value) storage.setItem('een_userProfile', JSON.stringify(userProfile.value))\n } catch (err: unknown) {\n // Storage might not be available (SSR, private browsing, etc.)\n debug('Failed to save to storage:', err instanceof Error ? err.message : String(err))\n }\n }\n\n function loadFromStorage() {\n try {\n const storage = getStorageAdapter()\n token.value = storage.getItem('een_token')\n const expStr = storage.getItem('een_tokenExpiration')\n tokenExpiration.value = expStr ? parseInt(expStr, 10) : null\n refreshTokenMarker.value = storage.getItem('een_refreshTokenMarker')\n sessionId.value = storage.getItem('een_sessionId')\n hostname.value = storage.getItem('een_hostname')\n const portStr = storage.getItem('een_port')\n port.value = portStr ? parseInt(portStr, 10) : 443\n const profileStr = storage.getItem('een_userProfile')\n userProfile.value = profileStr ? JSON.parse(profileStr) : null\n } catch (err: unknown) {\n // Storage might not be available (SSR, private browsing, etc.)\n debug('Failed to load from storage:', err instanceof Error ? err.message : String(err))\n }\n }\n\n function clearStorage() {\n try {\n const storage = getStorageAdapter()\n storage.removeItem('een_token')\n storage.removeItem('een_tokenExpiration')\n storage.removeItem('een_refreshTokenMarker')\n storage.removeItem('een_sessionId')\n storage.removeItem('een_hostname')\n storage.removeItem('een_port')\n storage.removeItem('een_userProfile')\n } catch (err: unknown) {\n // Storage might not be available (SSR, private browsing, etc.)\n debug('Failed to clear storage:', err instanceof Error ? err.message : String(err))\n }\n }\n\n return {\n // State\n token,\n tokenExpiration,\n refreshTokenMarker,\n sessionId,\n hostname,\n port,\n userProfile,\n isRefreshing,\n refreshFailed,\n refreshFailedMessage,\n\n // Computed\n isAuthenticated,\n baseUrl,\n isTokenExpired,\n tokenExpiresIn,\n\n // Actions\n setToken,\n setRefreshTokenMarker,\n setSessionId,\n setBaseUrl,\n setUserProfile,\n setupAutoRefresh,\n clearRefreshFailed,\n logout,\n initialize\n }\n})\n","import { useAuthStore } from './store'\nimport { getProxyUrl, getClientId, getRedirectUri } from '../config'\nimport { success, failure } from '../types'\nimport type { Result } from '../types'\nimport { debug } from '../utils/debug'\n\nconst EEN_AUTH_URL = 'https://auth.eagleeyenetworks.com/oauth2/authorize'\n\n/**\n * Token response from the OAuth proxy.\n *\n * @remarks\n * This is the response returned by the proxy's `/proxy/getAccessToken` endpoint\n * after successfully exchanging an authorization code for an access token.\n *\n * @category Authentication\n */\nexport interface TokenResponse {\n accessToken: string\n expiresIn: number\n httpsBaseUrl: string | { hostname: string; port?: number }\n userEmail: string\n sessionId: string\n}\n\n/**\n * Generate the OAuth authorization URL\n */\nexport function getAuthUrl(): string {\n const clientId = getClientId()\n if (!clientId) {\n throw new Error('Client ID not configured. Call initEenToolkit() or set VITE_EEN_CLIENT_ID')\n }\n\n // Generate and store state for CSRF protection\n const state = crypto.randomUUID()\n try {\n sessionStorage.setItem('een_oauth_state', state)\n } catch {\n // sessionStorage might not be available\n }\n\n const params = new URLSearchParams({\n client_id: clientId,\n response_type: 'code',\n scope: 'vms.all',\n redirect_uri: getRedirectUri(),\n state\n })\n\n debug('Generated auth URL with state:', state)\n return `${EEN_AUTH_URL}?${params.toString()}`\n}\n\n/**\n * Exchange authorization code for access token\n */\nexport async function getAccessToken(code: string): Promise<Result<TokenResponse>> {\n const proxyUrl = getProxyUrl()\n if (!proxyUrl) {\n return failure('AUTH_FAILED', 'Proxy URL not configured. Call initEenToolkit() or set VITE_PROXY_URL')\n }\n\n const params = new URLSearchParams({\n code,\n redirect_uri: getRedirectUri()\n })\n\n try {\n const response = await fetch(`${proxyUrl}/proxy/getAccessToken?${params.toString()}`, {\n method: 'POST',\n credentials: 'include',\n headers: {\n 'Accept': 'application/json'\n }\n })\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => 'Unknown error')\n return failure('AUTH_FAILED', `Token exchange failed: ${errorText}`, response.status)\n }\n\n const data = await response.json() as TokenResponse\n debug('Token received, expires in:', data.expiresIn)\n return success(data)\n } catch (err) {\n return failure('NETWORK_ERROR', `Failed to exchange code: ${String(err)}`)\n }\n}\n\n/**\n * Refresh the access token using stored refresh token\n */\nexport async function refreshToken(): Promise<Result<{ accessToken: string; expiresIn: number }>> {\n const proxyUrl = getProxyUrl()\n if (!proxyUrl) {\n return failure('AUTH_FAILED', 'Proxy URL not configured')\n }\n\n const authStore = useAuthStore()\n\n try {\n const headers: HeadersInit = {\n 'Accept': 'application/json'\n }\n\n // Add session ID header as fallback for environments where cookies don't work\n if (authStore.sessionId) {\n headers['Authorization'] = `Bearer ${authStore.sessionId}`\n }\n\n const response = await fetch(`${proxyUrl}/proxy/refreshAccessToken`, {\n method: 'POST',\n credentials: 'include',\n headers\n })\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => 'Unknown error')\n return failure('AUTH_FAILED', `Token refresh failed: ${errorText}`, response.status)\n }\n\n const data = await response.json() as { accessToken: string; expiresIn: number }\n\n // Update store with new token\n authStore.setToken(data.accessToken, data.expiresIn)\n\n debug('Token refreshed, expires in:', data.expiresIn)\n return success(data)\n } catch (err) {\n return failure('NETWORK_ERROR', `Failed to refresh token: ${String(err)}`)\n }\n}\n\n/**\n * Revoke the current token and logout\n */\nexport async function revokeToken(): Promise<Result<void>> {\n const proxyUrl = getProxyUrl()\n if (!proxyUrl) {\n return failure('AUTH_FAILED', 'Proxy URL not configured')\n }\n\n const authStore = useAuthStore()\n\n try {\n const headers: HeadersInit = {\n 'Accept': 'application/json'\n }\n\n if (authStore.sessionId) {\n headers['Authorization'] = `Bearer ${authStore.sessionId}`\n }\n\n const response = await fetch(`${proxyUrl}/proxy/revoke`, {\n method: 'POST',\n credentials: 'include',\n headers\n })\n\n // Logout regardless of response\n authStore.logout()\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => 'Unknown error')\n return failure('AUTH_FAILED', `Token revocation failed: ${errorText}`, response.status)\n }\n\n debug('Token revoked')\n return success(undefined)\n } catch (err) {\n // Still logout on error\n authStore.logout()\n return failure('NETWORK_ERROR', `Failed to revoke token: ${String(err)}`)\n }\n}\n\n/**\n * Handle OAuth callback - validates state and exchanges code for token\n */\nexport async function handleAuthCallback(code: string, state: string): Promise<Result<TokenResponse>> {\n // Validate state for CSRF protection\n let storedState: string | null = null\n try {\n storedState = sessionStorage.getItem('een_oauth_state')\n sessionStorage.removeItem('een_oauth_state')\n } catch {\n // sessionStorage might not be available\n }\n\n if (!storedState) {\n return failure('AUTH_FAILED', 'No OAuth state found. Please restart the login process.')\n }\n\n // Constant-time comparison to prevent timing attacks\n if (!constantTimeEquals(state, storedState)) {\n return failure('AUTH_FAILED', 'Invalid OAuth state. Possible CSRF attack.')\n }\n\n debug('State validated, exchanging code for token')\n\n // Exchange code for token\n const result = await getAccessToken(code)\n\n if (result.error) {\n return result\n }\n\n // Update auth store with received data\n const authStore = useAuthStore()\n const data = result.data\n\n authStore.setToken(data.accessToken, data.expiresIn)\n authStore.setRefreshTokenMarker('present')\n authStore.setSessionId(data.sessionId)\n authStore.setBaseUrl(data.httpsBaseUrl)\n\n debug('Auth callback complete, user:', data.userEmail)\n\n return success(data)\n}\n\n/**\n * Constant-time string comparison to prevent timing attacks\n */\nfunction constantTimeEquals(a: string, b: string): boolean {\n if (a.length !== b.length) {\n return false\n }\n\n let result = 0\n for (let i = 0; i < a.length; i++) {\n result |= a.charCodeAt(i) ^ b.charCodeAt(i)\n }\n\n return result === 0\n}\n","import { useAuthStore } from '../auth/store'\nimport { success, failure } from '../types'\nimport type { Result, PaginatedResult, User, UserProfile, ListUsersParams, GetUserParams } from '../types'\nimport { debug } from '../utils/debug'\n\n/**\n * Get the current authenticated user's profile.\n *\n * @remarks\n * Fetches the profile of the currently authenticated user from `/api/v3.0/users/self`.\n * The result is also stored in the auth store for easy access via `useAuthStore().userProfile`.\n *\n * @returns A Result containing the user profile or an error\n *\n * @example\n * ```typescript\n * import { getCurrentUser } from 'een-api-toolkit'\n *\n * const { data, error } = await getCurrentUser()\n *\n * if (error) {\n * if (error.code === 'AUTH_REQUIRED') {\n * router.push('/login')\n * }\n * return\n * }\n *\n * console.log(`Welcome, ${data.firstName} ${data.lastName}`)\n * ```\n *\n * @category Users\n */\nexport async function getCurrentUser(): Promise<Result<UserProfile>> {\n const authStore = useAuthStore()\n\n if (!authStore.isAuthenticated) {\n return failure('AUTH_REQUIRED', 'Authentication required')\n }\n\n if (!authStore.baseUrl) {\n return failure('AUTH_REQUIRED', 'Base URL not configured')\n }\n\n const url = `${authStore.baseUrl}/api/v3.0/users/self`\n debug('Fetching current user:', url)\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n 'Accept': 'application/json',\n 'Authorization': `Bearer ${authStore.token}`\n }\n })\n\n if (!response.ok) {\n return handleErrorResponse(response)\n }\n\n const data = await response.json() as UserProfile\n debug('Current user fetched:', data.email)\n\n // Update profile in store\n authStore.setUserProfile(data)\n\n return success(data)\n } catch (err) {\n return failure('NETWORK_ERROR', `Failed to fetch current user: ${String(err)}`)\n }\n}\n\n/**\n * List users with optional pagination and filtering.\n *\n * @remarks\n * Fetches a paginated list of users from `/api/v3.0/users`. Use the `pageSize`\n * parameter to control how many results are returned per page, and `pageToken`\n * to navigate to subsequent pages.\n *\n * For more details, see the\n * [EEN API Documentation](https://developer.eagleeyenetworks.com/reference/getusers).\n *\n * @param params - Optional pagination and filtering parameters\n * @returns A Result containing a paginated list of users or an error\n *\n * @example\n * ```typescript\n * import { getUsers } from 'een-api-toolkit'\n *\n * // Basic usage\n * const { data, error } = await getUsers()\n * if (data) {\n * console.log(`Found ${data.results.length} users`)\n * }\n *\n * // With pagination\n * const { data } = await getUsers({ pageSize: 50 })\n * if (data?.nextPageToken) {\n * const { data: page2 } = await getUsers({\n * pageSize: 50,\n * pageToken: data.nextPageToken\n * })\n * }\n *\n * // Fetch all users\n * let allUsers: User[] = []\n * let pageToken: string | undefined\n * do {\n * const { data, error } = await getUsers({ pageSize: 100, pageToken })\n * if (error) break\n * allUsers.push(...data.results)\n * pageToken = data.nextPageToken\n * } while (pageToken)\n * ```\n *\n * @category Users\n */\nexport async function getUsers(params?: ListUsersParams): Promise<Result<PaginatedResult<User>>> {\n const authStore = useAuthStore()\n\n if (!authStore.isAuthenticated) {\n return failure('AUTH_REQUIRED', 'Authentication required')\n }\n\n if (!authStore.baseUrl) {\n return failure('AUTH_REQUIRED', 'Base URL not configured')\n }\n\n const queryParams = new URLSearchParams()\n\n if (params?.pageSize) {\n queryParams.append('pageSize', String(params.pageSize))\n }\n if (params?.pageToken) {\n queryParams.append('pageToken', params.pageToken)\n }\n if (params?.include && params.include.length > 0) {\n queryParams.append('include', params.include.join(','))\n }\n\n const queryString = queryParams.toString()\n const url = `${authStore.baseUrl}/api/v3.0/users${queryString ? `?${queryString}` : ''}`\n debug('Fetching users:', url)\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n 'Accept': 'application/json',\n 'Authorization': `Bearer ${authStore.token}`\n }\n })\n\n if (!response.ok) {\n return handleErrorResponse(response)\n }\n\n const data = await response.json() as PaginatedResult<User>\n debug('Users fetched:', data.results?.length ?? 0, 'users')\n\n return success(data)\n } catch (err) {\n return failure('NETWORK_ERROR', `Failed to fetch users: ${String(err)}`)\n }\n}\n\n/**\n * Get a specific user by ID.\n *\n * @remarks\n * Fetches a single user from `/api/v3.0/users/{userId}`. Use the `include`\n * parameter to request additional fields like permissions.\n *\n * For more details, see the\n * [EEN API Documentation](https://developer.eagleeyenetworks.com/reference/getuser).\n *\n * @param userId - The unique identifier of the user to fetch\n * @param params - Optional parameters (e.g., include additional fields)\n * @returns A Result containing the user or an error\n *\n * @example\n * ```typescript\n * import { getUser } from 'een-api-toolkit'\n *\n * const { data, error } = await getUser('user-123')\n *\n * if (error) {\n * if (error.code === 'NOT_FOUND') {\n * console.log('User not found')\n * }\n * return\n * }\n *\n * console.log(`User: ${data.firstName} ${data.lastName}`)\n *\n * // With permissions\n * const { data: userWithPerms } = await getUser('user-123', {\n * include: ['permissions']\n * })\n * console.log('Permissions:', userWithPerms?.permissions)\n * ```\n *\n * @category Users\n */\nexport async function getUser(userId: string, params?: GetUserParams): Promise<Result<User>> {\n const authStore = useAuthStore()\n\n if (!authStore.isAuthenticated) {\n return failure('AUTH_REQUIRED', 'Authentication required')\n }\n\n if (!authStore.baseUrl) {\n return failure('AUTH_REQUIRED', 'Base URL not configured')\n }\n\n if (!userId) {\n return failure('VALIDATION_ERROR', 'User ID is required')\n }\n\n const queryParams = new URLSearchParams()\n\n if (params?.include && params.include.length > 0) {\n queryParams.append('include', params.include.join(','))\n }\n\n const queryString = queryParams.toString()\n const url = `${authStore.baseUrl}/api/v3.0/users/${encodeURIComponent(userId)}${queryString ? `?${queryString}` : ''}`\n debug('Fetching user:', url)\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n 'Accept': 'application/json',\n 'Authorization': `Bearer ${authStore.token}`\n }\n })\n\n if (!response.ok) {\n return handleErrorResponse(response)\n }\n\n const data = await response.json() as User\n debug('User fetched:', data.email)\n\n return success(data)\n } catch (err) {\n return failure('NETWORK_ERROR', `Failed to fetch user: ${String(err)}`)\n }\n}\n\n/**\n * Handle error responses from the API.\n * @internal\n */\nasync function handleErrorResponse<T>(response: Response): Promise<Result<T>> {\n const status = response.status\n\n let message: string\n try {\n const errorData = await response.json()\n message = errorData.message ?? errorData.error ?? response.statusText\n } catch {\n message = response.statusText || 'Unknown error'\n }\n\n switch (status) {\n case 401:\n return failure('AUTH_REQUIRED', `Authentication failed: ${message}`, status)\n case 403:\n return failure('FORBIDDEN', `Access denied: ${message}`, status)\n case 404:\n return failure('NOT_FOUND', `Not found: ${message}`, status)\n case 429:\n return failure('RATE_LIMITED', `Rate limited: ${message}`, status)\n default:\n return failure('API_ERROR', `API error: ${message}`, status)\n }\n}\n","import { useAuthStore } from '../auth/store'\nimport { success, failure } from '../types'\nimport type { Result, PaginatedResult, Camera, ListCamerasParams, GetCameraParams } from '../types'\nimport { debug } from '../utils/debug'\n\n/**\n * List cameras with optional pagination and filtering.\n *\n * @remarks\n * Fetches a paginated list of cameras from `/api/v3.0/cameras`. Supports\n * extensive filtering options for location, status, tags, and more.\n *\n * For more details, see the\n * [EEN API Documentation](https://developer.eagleeyenetworks.com/reference/listcameras).\n *\n * @param params - Optional pagination and filtering parameters\n * @returns A Result containing a paginated list of cameras or an error\n *\n * @example\n * ```typescript\n * import { getCameras } from 'een-api-toolkit'\n *\n * // Basic usage\n * const { data, error } = await getCameras()\n * if (data) {\n * console.log(`Found ${data.results.length} cameras`)\n * }\n *\n * // With filters\n * const { data } = await getCameras({\n * pageSize: 50,\n * status__in: ['online'],\n * include: ['deviceInfo', 'streamUrls']\n * })\n *\n * // Fetch all cameras\n * let allCameras: Camera[] = []\n * let pageToken: string | undefined\n * do {\n * const { data, error } = await getCameras({ pageSize: 100, pageToken })\n * if (error) break\n * allCameras.push(...data.results)\n * pageToken = data.nextPageToken\n * } while (pageToken)\n * ```\n *\n * @category Cameras\n */\nexport async function getCameras(params?: ListCamerasParams): Promise<Result<PaginatedResult<Camera>>> {\n const authStore = useAuthStore()\n\n if (!authStore.isAuthenticated) {\n return failure('AUTH_REQUIRED', 'Authentication required')\n }\n\n if (!authStore.baseUrl) {\n return failure('AUTH_REQUIRED', 'Base URL not configured')\n }\n\n const queryParams = new URLSearchParams()\n\n // Pagination\n if (params?.pageSize) {\n queryParams.append('pageSize', String(params.pageSize))\n }\n if (params?.pageToken) {\n queryParams.append('pageToken', params.pageToken)\n }\n\n // Include/Sort\n if (params?.include && params.include.length > 0) {\n queryParams.append('include', params.include.join(','))\n }\n if (params?.sort && params.sort.length > 0) {\n queryParams.append('sort', params.sort.join(','))\n }\n\n // Location/Bridge filters\n if (params?.locationId__in && params.locationId__in.length > 0) {\n queryParams.append('locationId__in', params.locationId__in.join(','))\n }\n if (params?.bridgeId__in && params.bridgeId__in.length > 0) {\n queryParams.append('bridgeId__in', params.bridgeId__in.join(','))\n }\n\n // Multi-camera filters\n if (params?.multiCameraId) {\n queryParams.append('multiCameraId', params.multiCameraId)\n }\n if (params?.multiCameraId__ne) {\n queryParams.append('multiCameraId__ne', params.multiCameraId__ne)\n }\n if (params?.multiCameraId__in && params.multiCameraId__in.length > 0) {\n queryParams.append('multiCameraId__in', params.multiCameraId__in.join(','))\n }\n\n // Tag/Package filters\n if (params?.tags__contains && params.tags__contains.length > 0) {\n queryParams.append('tags__contains', params.tags__contains.join(','))\n }\n if (params?.tags__any && params.tags__any.length > 0) {\n queryParams.append('tags__any', params.tags__any.join(','))\n }\n if (params?.packages__contains && params.packages__contains.length > 0) {\n queryParams.append('packages__contains', params.packages__contains.join(','))\n }\n\n // Name filters\n if (params?.name) {\n queryParams.append('name', params.name)\n }\n if (params?.name__contains) {\n queryParams.append('name__contains', params.name__contains)\n }\n if (params?.name__in && params.name__in.length > 0) {\n queryParams.append('name__in', params.name__in.join(','))\n }\n\n // ID filters\n if (params?.id__in && params.id__in.length > 0) {\n queryParams.append('id__in', params.id__in.join(','))\n }\n if (params?.id__notIn && params.id__notIn.length > 0) {\n queryParams.append('id__notIn', params.id__notIn.join(','))\n }\n if (params?.id__contains) {\n queryParams.append('id__contains', params.id__contains)\n }\n\n // Layout filter\n if (params?.layoutId) {\n queryParams.append('layoutId', params.layoutId)\n }\n\n // Share filters (use API nested field syntax)\n if (typeof params?.shared === 'boolean') {\n queryParams.append('shareDetails.shared', String(params.shared))\n }\n if (params?.sharedCameraAccount) {\n queryParams.append('shareDetails.accountId', params.sharedCameraAccount)\n }\n if (typeof params?.firstResponder === 'boolean') {\n queryParams.append('shareDetails.firstResponder', String(params.firstResponder))\n }\n\n // Device filters\n if (typeof params?.directToCloud === 'boolean') {\n queryParams.append('deviceInfo.directToCloud', String(params.directToCloud))\n }\n\n // Speaker filter\n if (params?.speakerId__in && params.speakerId__in.length > 0) {\n queryParams.append('speakerId__in', params.speakerId__in.join(','))\n }\n\n // Search\n if (params?.q) {\n queryParams.append('q', params.q)\n }\n if (typeof params?.qRelevance__gte === 'number') {\n queryParams.append('qRelevance__gte', String(params.qRelevance__gte))\n }\n\n // Analytics filter\n if (params?.enabledAnalytics__contains && params.enabledAnalytics__contains.length > 0) {\n queryParams.append('enabledAnalytics__contains', params.enabledAnalytics__contains.join(','))\n }\n\n // Status filters\n if (params?.status__in && params.status__in.length > 0) {\n queryParams.append('status__in', params.status__in.join(','))\n }\n if (params?.status__ne) {\n queryParams.append('status__ne', params.status__ne)\n }\n\n const queryString = queryParams.toString()\n const url = `${authStore.baseUrl}/api/v3.0/cameras${queryString ? `?${queryString}` : ''}`\n debug('Fetching cameras:', url)\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n 'Accept': 'application/json',\n 'Authorization': `Bearer ${authStore.token}`\n }\n })\n\n if (!response.ok) {\n return handleErrorResponse(response)\n }\n\n const data = await response.json() as PaginatedResult<Camera>\n debug('Cameras fetched:', data.results?.length ?? 0, 'cameras')\n\n return success(data)\n } catch (err) {\n return failure('NETWORK_ERROR', `Failed to fetch cameras: ${String(err)}`)\n }\n}\n\n/**\n * Get a specific camera by ID.\n *\n * @remarks\n * Fetches a single camera from `/api/v3.0/cameras/{cameraId}`. Use the `include`\n * parameter to request additional fields.\n *\n * For more details, see the\n * [EEN API Documentation](https://developer.eagleeyenetworks.com/reference/getcamera).\n *\n * @param cameraId - The unique identifier of the camera to fetch\n * @param params - Optional parameters (e.g., include additional fields)\n * @returns A Result containing the camera or an error\n *\n * @example\n * ```typescript\n * import { getCamera } from 'een-api-toolkit'\n *\n * const { data, error } = await getCamera('camera-123')\n *\n * if (error) {\n * if (error.code === 'NOT_FOUND') {\n * console.log('Camera not found')\n * }\n * return\n * }\n *\n * console.log(`Camera: ${data.name} (${data.status})`)\n *\n * // With additional fields\n * const { data: cameraWithDetails } = await getCamera('camera-123', {\n * include: ['deviceInfo', 'streamUrls', 'shareDetails']\n * })\n * ```\n *\n * @category Cameras\n */\nexport async function getCamera(cameraId: string, params?: GetCameraParams): Promise<Result<Camera>> {\n const authStore = useAuthStore()\n\n if (!authStore.isAuthenticated) {\n return failure('AUTH_REQUIRED', 'Authentication required')\n }\n\n if (!authStore.baseUrl) {\n return failure('AUTH_REQUIRED', 'Base URL not configured')\n }\n\n if (!cameraId) {\n return failure('VALIDATION_ERROR', 'Camera ID is required')\n }\n\n const queryParams = new URLSearchParams()\n\n if (params?.include && params.include.length > 0) {\n queryParams.append('include', params.include.join(','))\n }\n\n const queryString = queryParams.toString()\n const url = `${authStore.baseUrl}/api/v3.0/cameras/${encodeURIComponent(cameraId)}${queryString ? `?${queryString}` : ''}`\n debug('Fetching camera:', url)\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n 'Accept': 'application/json',\n 'Authorization': `Bearer ${authStore.token}`\n }\n })\n\n if (!response.ok) {\n return handleErrorResponse(response)\n }\n\n const data = await response.json() as Camera\n debug('Camera fetched:', data.name)\n\n return success(data)\n } catch (err) {\n return failure('NETWORK_ERROR', `Failed to fetch camera: ${String(err)}`)\n }\n}\n\n/**\n * Handle error responses from the API.\n * @internal\n */\nasync function handleErrorResponse<T>(response: Response): Promise<Result<T>> {\n const status = response.status\n\n let message: string\n try {\n const errorData = await response.json()\n message = errorData.message ?? errorData.error ?? response.statusText\n } catch (parseError) {\n debug('Failed to parse error response JSON:', parseError)\n message = response.statusText || 'Unknown error'\n }\n\n switch (status) {\n case 401:\n return failure('AUTH_REQUIRED', `Authentication failed: ${message}`, status)\n case 403:\n return failure('FORBIDDEN', `Access denied: ${message}`, status)\n case 404:\n return failure('NOT_FOUND', `Not found: ${message}`, status)\n case 429:\n return failure('RATE_LIMITED', `Rate limited: ${message}`, status)\n default:\n return failure('API_ERROR', `API error: ${message}`, status)\n }\n}\n","import { useAuthStore } from '../auth/store'\nimport { success, failure } from '../types'\nimport type { Result, PaginatedResult, Bridge, ListBridgesParams, GetBridgeParams } from '../types'\nimport { debug } from '../utils/debug'\n\n/**\n * List bridges with optional pagination and filtering.\n *\n * @remarks\n * Fetches a paginated list of bridges from `/api/v3.0/bridges`. Supports\n * filtering options for location, status, tags, and more.\n *\n * For more details, see the\n * [EEN API Documentation](https://developer.eagleeyenetworks.com/reference/listbridges).\n *\n * @param params - Optional pagination and filtering parameters\n * @returns A Result containing a paginated list of bridges or an error\n *\n * @example\n * ```typescript\n * import { getBridges } from 'een-api-toolkit'\n *\n * // Basic usage\n * const { data, error } = await getBridges()\n * if (data) {\n * console.log(`Found ${data.results.length} bridges`)\n * }\n *\n * // With filters\n * const { data } = await getBridges({\n * pageSize: 50,\n * status__in: ['online'],\n * include: ['deviceInfo', 'networkInfo']\n * })\n *\n * // Fetch all bridges\n * let allBridges: Bridge[] = []\n * let pageToken: string | undefined\n * do {\n * const { data, error } = await getBridges({ pageSize: 100, pageToken })\n * if (error) break\n * allBridges.push(...data.results)\n * pageToken = data.nextPageToken\n * } while (pageToken)\n * ```\n *\n * @category Bridges\n */\nexport async function getBridges(params?: ListBridgesParams): Promise<Result<PaginatedResult<Bridge>>> {\n const authStore = useAuthStore()\n\n if (!authStore.isAuthenticated) {\n return failure('AUTH_REQUIRED', 'Authentication required')\n }\n\n if (!authStore.baseUrl) {\n return failure('AUTH_REQUIRED', 'Base URL not configured')\n }\n\n const queryParams = new URLSearchParams()\n\n // Pagination\n if (params?.pageSize) {\n queryParams.append('pageSize', String(params.pageSize))\n }\n if (params?.pageToken) {\n queryParams.append('pageToken', params.pageToken)\n }\n\n // Include/Sort\n if (params?.include && params.include.length > 0) {\n queryParams.append('include', params.include.join(','))\n }\n if (params?.sort && params.sort.length > 0) {\n queryParams.append('sort', params.sort.join(','))\n }\n\n // Location filters\n if (params?.locationId__in && params.locationId__in.length > 0) {\n queryParams.append('locationId__in', params.locationId__in.join(','))\n }\n\n // Tag filters\n if (params?.tags__contains && params.tags__contains.length > 0) {\n queryParams.append('tags__contains', params.tags__contains.join(','))\n }\n if (params?.tags__any && params.tags__any.length > 0) {\n queryParams.append('tags__any', params.tags__any.join(','))\n }\n\n // Name filters\n if (params?.name) {\n queryParams.append('name', params.name)\n }\n if (params?.name__contains) {\n queryParams.append('name__contains', params.name__contains)\n }\n if (params?.name__in && params.name__in.length > 0) {\n queryParams.append('name__in', params.name__in.join(','))\n }\n\n // ID filters\n if (params?.id__in && params.id__in.length > 0) {\n queryParams.append('id__in', params.id__in.join(','))\n }\n if (params?.id__notIn && params.id__notIn.length > 0) {\n queryParams.append('id__notIn', params.id__notIn.join(','))\n }\n\n // Search\n if (params?.q) {\n queryParams.append('q', params.q)\n }\n if (typeof params?.qRelevance__gte === 'number') {\n queryParams.append('qRelevance__gte', String(params.qRelevance__gte))\n }\n\n // Status filters\n if (params?.status__in && params.status__in.length > 0) {\n queryParams.append('status__in', params.status__in.join(','))\n }\n if (params?.status__ne) {\n queryParams.append('status__ne', params.status__ne)\n }\n\n const queryString = queryParams.toString()\n const url = `${authStore.baseUrl}/api/v3.0/bridges${queryString ? `?${queryString}` : ''}`\n debug('Fetching bridges:', url)\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n 'Accept': 'application/json',\n 'Authorization': `Bearer ${authStore.token}`\n }\n })\n\n if (!response.ok) {\n return handleErrorResponse(response)\n }\n\n const data = await response.json() as PaginatedResult<Bridge>\n debug('Bridges fetched:', data.results?.length ?? 0, 'bridges')\n\n return success(data)\n } catch (err) {\n return failure('NETWORK_ERROR', `Failed to fetch bridges: ${String(err)}`)\n }\n}\n\n/**\n * Get a specific bridge by ID.\n *\n * @remarks\n * Fetches a single bridge from `/api/v3.0/bridges/{bridgeId}`. Use the `include`\n * parameter to request additional fields.\n *\n * For more details, see the\n * [EEN API Documentation](https://developer.eagleeyenetworks.com/reference/getbridge).\n *\n * @param bridgeId - The unique identifier of the bridge to fetch\n * @param params - Optional parameters (e.g., include additional fields)\n * @returns A Result containing the bridge or an error\n *\n * @example\n * ```typescript\n * import { getBridge } from 'een-api-toolkit'\n *\n * const { data, error } = await getBridge('bridge-123')\n *\n * if (error) {\n * if (error.code === 'NOT_FOUND') {\n * console.log('Bridge not found')\n * }\n * return\n * }\n *\n * console.log(`Bridge: ${data.name} (${data.status})`)\n *\n * // With additional fields\n * const { data: bridgeWithDetails } = await getBridge('bridge-123', {\n * include: ['deviceInfo', 'networkInfo', 'status']\n * })\n * ```\n *\n * @category Bridges\n */\nexport async function getBridge(bridgeId: string, params?: GetBridgeParams): Promise<Result<Bridge>> {\n const authStore = useAuthStore()\n\n if (!authStore.isAuthenticated) {\n return failure('AUTH_REQUIRED', 'Authentication required')\n }\n\n if (!authStore.baseUrl) {\n return failure('AUTH_REQUIRED', 'Base URL not configured')\n }\n\n if (!bridgeId) {\n return failure('VALIDATION_ERROR', 'Bridge ID is required')\n }\n\n const queryParams = new URLSearchParams()\n\n if (params?.include && params.include.length > 0) {\n queryParams.append('include', params.include.join(','))\n }\n\n const queryString = queryParams.toString()\n const url = `${authStore.baseUrl}/api/v3.0/bridges/${encodeURIComponent(bridgeId)}${queryString ? `?${queryString}` : ''}`\n debug('Fetching bridge:', url)\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n 'Accept': 'application/json',\n 'Authorization': `Bearer ${authStore.token}`\n }\n })\n\n if (!response.ok) {\n return handleErrorResponse(response)\n }\n\n const data = await response.json() as Bridge\n debug('Bridge fetched:', data.name)\n\n return success(data)\n } catch (err) {\n return failure('NETWORK_ERROR', `Failed to fetch bridge: ${String(err)}`)\n }\n}\n\n/**\n * Handle error responses from the API.\n * @internal\n */\nasync function handleErrorResponse<T>(response: Response): Promise<Result<T>> {\n const status = response.status\n\n let message: string\n try {\n const errorData = await response.json()\n message = errorData.message ?? errorData.error ?? response.statusText\n } catch (parseError) {\n debug('Failed to parse error response JSON:', parseError)\n message = response.statusText || 'Unknown error'\n }\n\n switch (status) {\n case 401:\n return failure('AUTH_REQUIRED', `Authentication failed: ${message}`, status)\n case 403:\n return failure('FORBIDDEN', `Access denied: ${message}`, status)\n case 404:\n return failure('NOT_FOUND', `Not found: ${message}`, status)\n case 429:\n return failure('RATE_LIMITED', `Rate limited: ${message}`, status)\n default:\n return failure('API_ERROR', `API error: ${message}`, status)\n }\n}\n","import { useAuthStore } from '../auth/store'\nimport { success, failure } from '../types'\nimport type {\n Result,\n PaginatedResult,\n MediaInterval,\n ListMediaParams,\n GetLiveImageParams,\n GetRecordedImageParams,\n LiveImageResult,\n RecordedImageResult,\n MediaSessionResponse,\n MediaSessionResult\n} from '../types'\nimport { debug } from '../utils/debug'\n\n/** Default timeout for media requests in milliseconds */\nconst DEFAULT_TIMEOUT_MS = 30000\n\n/**\n * Create an AbortController with a timeout.\n * @internal\n */\nfunction createTimeoutController(timeoutMs: number = DEFAULT_TIMEOUT_MS): { controller: AbortController; timeoutId: ReturnType<typeof setTimeout> } {\n const controller = new AbortController()\n const timeoutId = setTimeout(() => controller.abort(), timeoutMs)\n return { controller, timeoutId }\n}\n\n/**\n * Convert ArrayBuffer to base64 string.\n *\n * @remarks\n * **Memory Considerations**: This function loads the entire image into memory\n * as a string. For typical camera preview images (<500KB), this is efficient.\n * For larger images (>2MB), consider streaming or chunked processing in the\n * consuming application. Base64 encoding adds ~33% size overhead.\n *\n * @internal\n */\nfunction arrayBufferToBase64(buffer: ArrayBuffer): string {\n const bytes = new Uint8Array(buffer)\n // Use chunked approach with array join for O(n) complexity instead of O(n²) string concatenation\n // Iterate byte-by-byte within chunks to avoid call stack issues with String.fromCharCode.apply()\n const chunkSize = 8192\n const chunks: string[] = []\n for (let i = 0; i < bytes.byteLength; i += chunkSize) {\n const chunk = bytes.subarray(i, Math.min(i + chunkSize, bytes.byteLength))\n let str = ''\n for (let j = 0; j < chunk.length; j++) {\n str += String.fromCharCode(chunk[j]!)\n }\n chunks.push(str)\n }\n const binary = chunks.join('')\n // Use btoa in browser, Buffer in Node.js\n if (typeof btoa === 'function') {\n return btoa(binary)\n }\n return Buffer.from(binary, 'binary').toString('base64')\n}\n\n/**\n * List media intervals (recording periods) for a device.\n *\n * @remarks\n * Fetches a paginated list of time intervals for which recordings exist.\n * Use this to find available recordings for a camera.\n *\n * For more details, see the\n * [EEN API Documentation](https://developer.eagleeyenetworks.com/reference/listmedia).\n *\n * @param params - Required parameters including deviceId, type, mediaType, and startTimestamp\n * @returns A Result containing a paginated list of media intervals or an error\n *\n * @example\n * ```typescript\n * import { listMedia } from 'een-api-toolkit'\n *\n * // Get video recordings from the last hour\n * const { data, error } = await listMedia({\n * deviceId: 'camera-123',\n * type: 'preview',\n * mediaType: 'video',\n * startTimestamp: new Date(Date.now() - 3600000).toISOString()\n * })\n *\n * if (data) {\n * console.log(`Found ${data.results.length} recording intervals`)\n * data.results.forEach(interval => {\n * console.log(`${interval.startTimestamp} - ${interval.endTimestamp}`)\n * })\n * }\n * ```\n *\n * @category Media\n */\nexport async function listMedia(params: ListMediaParams): Promise<Result<PaginatedResult<MediaInterval>>> {\n const authStore = useAuthStore()\n\n if (!authStore.isAuthenticated) {\n return failure('AUTH_REQUIRED', 'Authentication required')\n }\n\n if (!authStore.baseUrl) {\n return failure('AUTH_REQUIRED', 'Base URL not configured')\n }\n\n // Validate required parameters\n if (!params.deviceId) {\n return failure('VALIDATION_ERROR', 'Device ID is required')\n }\n if (!params.type) {\n return failure('VALIDATION_ERROR', 'Stream type is required (preview or main)')\n }\n if (!params.mediaType) {\n return failure('VALIDATION_ERROR', 'Media type is required (video or image)')\n }\n if (!params.startTimestamp) {\n return failure('VALIDATION_ERROR', 'Start timestamp is required')\n }\n\n const queryParams = new URLSearchParams()\n\n // Required parameters\n queryParams.append('deviceId', params.deviceId)\n queryParams.append('type', params.type)\n queryParams.append('mediaType', params.mediaType)\n queryParams.append('startTimestamp__gte', params.startTimestamp)\n\n // Optional parameters\n if (params.endTimestamp) {\n queryParams.append('endTimestamp__lte', params.endTimestamp)\n }\n if (typeof params.coalesce === 'boolean') {\n queryParams.append('coalesce', String(params.coalesce))\n }\n if (params.include && params.include.length > 0) {\n queryParams.append('include', params.include.join(','))\n }\n if (params.pageToken) {\n queryParams.append('pageToken', params.pageToken)\n }\n if (typeof params.pageSize === 'number') {\n queryParams.append('pageSize', String(params.pageSize))\n }\n\n const url = `${authStore.baseUrl}/api/v3.0/media?${queryParams.toString()}`\n debug('Fetching media intervals:', url)\n\n const { controller, timeoutId } = createTimeoutController()\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n 'Accept': 'application/json',\n 'Authorization': `Bearer ${authStore.token}`\n },\n signal: controller.signal\n })\n\n if (!response.ok) {\n return handleErrorResponse(response)\n }\n\n const data = await response.json() as PaginatedResult<MediaInterval>\n debug('Media intervals fetched:', data.results?.length ?? 0, 'intervals')\n\n return success(data)\n } catch (err) {\n if (err instanceof Error && err.name === 'AbortError') {\n return failure('NETWORK_ERROR', 'Request timed out')\n }\n return failure('NETWORK_ERROR', `Failed to fetch media intervals: ${String(err)}`)\n } finally {\n clearTimeout(timeoutId)\n }\n}\n\n/**\n * Get a live image from a camera.\n *\n * @remarks\n * Fetches a new live image from the specified camera. This call waits until\n * a new image is available from the device. The image is returned as a\n * base64 data URL that can be used directly in an HTML img element.\n *\n * Note: Live images only support the 'preview' stream type.\n *\n * **Memory Considerations**: Images are loaded into memory and base64 encoded,\n * adding ~33% size overhead. Typical preview images are <500KB. For high-frequency\n * polling, consider implementing error backoff and limiting concurrent requests.\n *\n * For more details, see the\n * [EEN API Documentation](https://developer.eagleeyenetworks.com/reference/getliveimage).\n *\n * @param params - Parameters including the required deviceId\n * @returns A Result containing the live image data or an error\n *\n * @example\n * ```typescript\n * import { getLiveImage } from 'een-api-toolkit'\n *\n * const { data, error } = await getLiveImage({ deviceId: 'camera-123' })\n *\n * if (data) {\n * // Display in an img element\n * document.getElementById('cameraImage').src = data.imageData\n * console.log('Image timestamp:', data.timestamp)\n * }\n *\n * // Continuously update the image with proper error handling\n * let isRunning = true\n * async function refreshLoop() {\n * const imgElement = document.getElementById('cameraImage') as HTMLImageElement\n * while (isRunning) {\n * const { data, error } = await getLiveImage({ deviceId: 'camera-123' })\n * if (error) {\n * console.error('Refresh failed:', error.message)\n * break // Stop on error\n * }\n * if (data) {\n * imgElement.src = data.imageData\n * }\n * await new Promise(r => setTimeout(r, 1000))\n * }\n * }\n * // Call refreshLoop() to start, set isRunning = false to stop\n * ```\n *\n * @category Media\n */\nexport async function getLiveImage(params: GetLiveImageParams): Promise<Result<LiveImageResult>> {\n const authStore = useAuthStore()\n\n if (!authStore.isAuthenticated) {\n return failure('AUTH_REQUIRED', 'Authentication required')\n }\n\n if (!authStore.baseUrl) {\n return failure('AUTH_REQUIRED', 'Base URL not configured')\n }\n\n if (!params.deviceId) {\n return failure('VALIDATION_ERROR', 'Device ID is required')\n }\n\n // Live images only support 'preview' type (enforced by TypeScript)\n const type = params.type ?? 'preview'\n\n const queryParams = new URLSearchParams()\n queryParams.append('deviceId', params.deviceId)\n queryParams.append('type', type)\n\n const url = `${authStore.baseUrl}/api/v3.0/media/liveImage.jpeg?${queryParams.toString()}`\n debug('Fetching live image:', url)\n\n const { controller, timeoutId } = createTimeoutController()\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n 'Accept': 'image/jpeg',\n 'Authorization': `Bearer ${authStore.token}`\n },\n signal: controller.signal\n })\n\n // Get headers before checking response.ok\n const timestamp = response.headers.get('X-Een-Timestamp')\n const prevToken = response.headers.get('X-Een-PrevToken')\n\n if (!response.ok) {\n return handleErrorResponse(response)\n }\n\n // Get image as base64\n const arrayBuffer = await response.arrayBuffer()\n const base64 = arrayBufferToBase64(arrayBuffer)\n const imageData = `data:image/jpeg;base64,${base64}`\n\n debug('Live image fetched, timestamp:', timestamp)\n\n return success({\n imageData,\n timestamp,\n prevToken\n })\n } catch (err) {\n if (err instanceof Error && err.name === 'AbortError') {\n return failure('NETWORK_ERROR', 'Request timed out')\n }\n return failure('NETWORK_ERROR', `Failed to fetch live image: ${String(err)}`)\n } finally {\n clearTimeout(timeoutId)\n }\n}\n\n/**\n * Get a recorded image from a camera.\n *\n * @remarks\n * Fetches a recorded image from the specified camera at a specific timestamp.\n * You can specify the desired timestamp using various operators (exact, gte, lte, etc.)\n * or use a pageToken from a previous request to navigate through images.\n *\n * The image is returned as a base64 data URL that can be used directly in an HTML img element.\n *\n * Note: The 'main' type is rate-limited and requires an actual recording at the timestamp.\n *\n * For more details, see the\n * [EEN API Documentation](https://developer.eagleeyenetworks.com/reference/getrecordedimage).\n *\n * @param params - Parameters including deviceId/pageToken and timestamp options\n * @returns A Result containing the recorded image data or an error\n *\n * @example\n * ```typescript\n * import { getRecordedImage } from 'een-api-toolkit'\n *\n * // Get image at or after a specific time\n * const { data, error } = await getRecordedImage({\n * deviceId: 'camera-123',\n * type: 'preview',\n * timestamp__gte: '2024-01-15T10:00:00.000Z'\n * })\n *\n * if (data) {\n * imgElement.src = data.imageData\n * console.log('Actual timestamp:', data.timestamp)\n *\n * // Get the next image using the token\n * if (data.nextToken) {\n * const { data: nextImage } = await getRecordedImage({\n * pageToken: data.nextToken\n * })\n * }\n * }\n * ```\n *\n * @category Media\n */\nexport async function getRecordedImage(params: GetRecordedImageParams): Promise<Result<RecordedImageResult>> {\n const authStore = useAuthStore()\n\n if (!authStore.isAuthenticated) {\n return failure('AUTH_REQUIRED', 'Authentication required')\n }\n\n if (!authStore.baseUrl) {\n return failure('AUTH_REQUIRED', 'Base URL not configured')\n }\n\n // Validate: either deviceId or pageToken is required\n if (!params.deviceId && !params.pageToken) {\n return failure('VALIDATION_ERROR', 'Either deviceId or pageToken is required')\n }\n\n // If not using pageToken, validate at least one timestamp parameter\n if (!params.pageToken) {\n const hasTimestamp = params.timestamp__lt || params.timestamp__lte ||\n params.timestamp || params.timestamp__gte || params.timestamp__gt\n if (!hasTimestamp) {\n return failure('VALIDATION_ERROR', 'At least one timestamp parameter is required')\n }\n }\n\n // Validate overlay requirements\n if (params.include?.includes('overlaySvgHeader') &&\n (!params.overlayId__in || params.overlayId__in.length === 0)) {\n return failure('VALIDATION_ERROR', 'At least one overlayId must be provided when requesting overlay headers')\n }\n\n const queryParams = new URLSearchParams()\n\n // Add parameters\n if (params.deviceId) {\n queryParams.append('deviceId', params.deviceId)\n }\n if (params.pageToken) {\n queryParams.append('pageToken', params.pageToken)\n }\n if (params.type) {\n queryParams.append('type', params.type)\n }\n\n // Timestamp parameters\n if (params.timestamp__lt) {\n queryParams.append('timestamp__lt', params.timestamp__lt)\n }\n if (params.timestamp__lte) {\n queryParams.append('timestamp__lte', params.timestamp__lte)\n }\n if (params.timestamp) {\n queryParams.append('timestamp', params.timestamp)\n }\n if (params.timestamp__gte) {\n queryParams.append('timestamp__gte', params.timestamp__gte)\n }\n if (params.timestamp__gt) {\n queryParams.append('timestamp__gt', params.timestamp__gt)\n }\n\n // Overlay parameters\n if (params.overlayId__in && params.overlayId__in.length > 0) {\n queryParams.append('overlayId__in', params.overlayId__in.join(','))\n }\n if (params.include && params.include.length > 0) {\n queryParams.append('include', params.include.join(','))\n }\n\n // Size parameters\n if (typeof params.targetWidth === 'number') {\n queryParams.append('targetWidth', String(params.targetWidth))\n }\n if (typeof params.targetHeight === 'number') {\n queryParams.append('targetHeight', String(params.targetHeight))\n }\n\n const url = `${authStore.baseUrl}/api/v3.0/media/recordedImage.jpeg?${queryParams.toString()}`\n debug('Fetching recorded image:', url)\n\n const { controller, timeoutId } = createTimeoutController()\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n 'Accept': 'image/jpeg',\n 'Authorization': `Bearer ${authStore.token}`\n },\n signal: controller.signal\n })\n\n // Get headers before checking response.ok\n const timestamp = response.headers.get('X-Een-Timestamp')\n const nextToken = response.headers.get('X-Een-NextToken')\n const prevToken = response.headers.get('X-Een-PrevToken')\n const overlaySvg = response.headers.get('X-Een-OverlaySvg')\n\n if (!response.ok) {\n return handleErrorResponse(response)\n }\n\n // Get image as base64\n const arrayBuffer = await response.arrayBuffer()\n const base64 = arrayBufferToBase64(arrayBuffer)\n const imageData = `data:image/jpeg;base64,${base64}`\n\n debug('Recorded image fetched, timestamp:', timestamp)\n\n return success({\n imageData,\n timestamp,\n nextToken,\n prevToken,\n overlaySvg\n })\n } catch (err) {\n if (err instanceof Error && err.name === 'AbortError') {\n return failure('NETWORK_ERROR', 'Request timed out')\n }\n return failure('NETWORK_ERROR', `Failed to fetch recorded image: ${String(err)}`)\n } finally {\n clearTimeout(timeoutId)\n }\n}\n\n/**\n * Handle error responses from the API.\n * @internal\n */\nasync function handleErrorResponse<T>(response: Response): Promise<Result<T>> {\n const status = response.status\n\n let message: string\n try {\n const errorData = await response.json()\n message = errorData.message ?? errorData.error ?? response.statusText\n } catch {\n message = response.statusText || 'Unknown error'\n }\n\n switch (status) {\n case 401:\n return failure('AUTH_REQUIRED', `Authentication failed: ${message}`, status)\n case 403:\n return failure('FORBIDDEN', `Access denied: ${message}`, status)\n case 404:\n return failure('NOT_FOUND', `Not found: ${message}`, status)\n case 429:\n return failure('RATE_LIMITED', `Rate limited: ${message}`, status)\n case 503:\n return failure('SERVICE_UNAVAILABLE', `Service unavailable: ${message}`, status)\n default:\n return failure('API_ERROR', `API error: ${message}`, status)\n }\n}\n\n/**\n * Get the media session URL for setting cookies.\n *\n * @remarks\n * Fetches the URL needed to set the media session cookie. The returned URL\n * must be called separately (with credentials included) to actually set the\n * cookie. This is the first step in the two-step media session initialization\n * process.\n *\n * For most use cases, prefer using {@link initMediaSession} which handles\n * both steps automatically.\n *\n * For more details, see the\n * [EEN API Documentation](https://developer.eagleeyenetworks.com/docs/watch-live-video).\n *\n * @returns A Result containing the media session URL or an error\n *\n * @example\n * ```typescript\n * import { getMediaSession } from 'een-api-toolkit'\n *\n * // Get the session URL (step 1)\n * const { data, error } = await getMediaSession()\n *\n * if (data) {\n * console.log('Session URL:', data.url)\n * // Now call data.url with credentials: 'include' to set the cookie\n * }\n * ```\n *\n * @category Media\n */\nexport async function getMediaSession(): Promise<Result<MediaSessionResponse>> {\n const authStore = useAuthStore()\n\n if (!authStore.isAuthenticated) {\n return failure('AUTH_REQUIRED', 'Authentication required')\n }\n\n if (!authStore.baseUrl) {\n return failure('AUTH_REQUIRED', 'Base URL not configured')\n }\n\n const url = `${authStore.baseUrl}/api/v3.0/media/session`\n debug('Fetching media session:', url)\n\n const { controller, timeoutId } = createTimeoutController()\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n 'Accept': 'application/json',\n 'Authorization': `Bearer ${authStore.token}`\n },\n signal: controller.signal\n })\n\n if (!response.ok) {\n return handleErrorResponse(response)\n }\n\n const data = await response.json() as MediaSessionResponse\n debug('Media session URL received:', data.url)\n\n return success(data)\n } catch (err) {\n if (err instanceof Error && err.name === 'AbortError') {\n return failure('NETWORK_ERROR', 'Request timed out')\n }\n return failure('NETWORK_ERROR', `Failed to fetch media session: ${String(err)}`)\n } finally {\n clearTimeout(timeoutId)\n }\n}\n\n/**\n * Initialize the media session by setting the session cookie.\n *\n * @remarks\n * This function handles the two-step process of setting up a media session:\n * 1. Fetches the session URL from `/api/v3.0/media/session`\n * 2. Calls that URL with credentials to set the session cookie\n *\n * Once the session cookie is set, the browser can access media streams\n * (like multipart preview URLs) without explicit Authorization headers.\n * This is required for using media URLs directly in HTML elements like\n * `<img>` or `<video>`.\n *\n * **Important**: This function must be called in a browser environment\n * where cookies can be set. It uses `credentials: 'include'` to ensure\n * the cookie is stored.\n *\n * For more details, see the\n * [EEN API Documentation](https://developer.eagleeyenetworks.com/docs/watch-live-video).\n *\n * @returns A Result containing the session result or an error\n *\n * @example\n * ```typescript\n * import { initMediaSession, listFeeds } from 'een-api-toolkit'\n *\n * // Initialize the media session (do this once after login)\n * const { data, error } = await initMediaSession()\n *\n * if (error) {\n * console.error('Failed to init media session:', error.message)\n * return\n * }\n *\n * // Now you can use multipart URLs directly in <img> elements\n * const { data: feeds } = await listFeeds({\n * deviceId: 'camera-123',\n * include: ['multipartUrl']\n * })\n *\n * if (feeds?.results[0]?.multipartUrl) {\n * // This works because the session cookie is set\n * imgElement.src = feeds.results[0].multipartUrl\n * }\n * ```\n *\n * @category Media\n */\nexport async function initMediaSession(): Promise<Result<MediaSessionResult>> {\n const authStore = useAuthStore()\n\n if (!authStore.isAuthenticated) {\n return failure('AUTH_REQUIRED', 'Authentication required')\n }\n\n // Step 1: Get the media session URL\n const sessionResult = await getMediaSession()\n\n if (sessionResult.error) {\n return failure(\n sessionResult.error.code,\n `Failed to get media session: ${sessionResult.error.message}`,\n sessionResult.error.status\n )\n }\n\n if (!sessionResult.data?.url) {\n return failure('API_ERROR', 'No session URL returned from media session endpoint')\n }\n\n const sessionUrl = sessionResult.data.url\n debug('Calling session URL to set cookie:', sessionUrl)\n\n const { controller, timeoutId } = createTimeoutController()\n\n try {\n // Step 2: Call the session URL to set the cookie\n const response = await fetch(sessionUrl, {\n method: 'GET',\n credentials: 'include', // Critical: include cookies in the request/response\n headers: {\n 'Accept': '*/*',\n 'Authorization': `Bearer ${authStore.token}`\n },\n signal: controller.signal\n })\n\n // The session endpoint typically returns 204 No Content on success\n // but may also return 200 OK\n if (!response.ok && response.status !== 204) {\n const status = response.status\n\n let message: string\n try {\n const errorData = await response.json()\n message = errorData.message ?? errorData.error ?? response.statusText\n } catch {\n message = response.statusText || 'Unknown error'\n }\n\n return failure('API_ERROR', `Failed to set media session cookie: ${message}`, status)\n }\n\n debug('Media session cookie set successfully')\n\n return success({\n success: true,\n sessionUrl\n })\n } catch (err) {\n if (err instanceof Error && err.name === 'AbortError') {\n return failure('NETWORK_ERROR', 'Request timed out while setting session cookie')\n }\n return failure('NETWORK_ERROR', `Failed to set media session cookie: ${String(err)}`)\n } finally {\n clearTimeout(timeoutId)\n }\n}\n","import { useAuthStore } from '../auth/store'\nimport { success, failure } from '../types'\nimport type { Result, ListFeedsParams, ListFeedsResult } from '../types'\nimport { debug } from '../utils/debug'\n\n/**\n * List feeds with optional filtering and pagination.\n *\n * @remarks\n * Fetches a list of feeds from `/api/v3.0/feeds`. Feeds represent live or\n * recorded streams from devices (cameras, speakers). Use the `include` parameter\n * to request specific streaming URLs.\n *\n * A single device can have multiple feeds (main, preview, talkdown) with\n * different quality levels and purposes.\n *\n * For more details, see the\n * [EEN API Documentation](https://developer.eagleeyenetworks.com/reference/listfeeds).\n *\n * @param params - Optional filtering and pagination parameters\n * @returns A Result containing a list of feeds or an error\n *\n * @example\n * ```typescript\n * import { listFeeds } from 'een-api-toolkit'\n * import type { Feed } from 'een-api-toolkit'\n *\n * // Get all feeds\n * const { data, error } = await listFeeds()\n * if (data) {\n * console.log(`Found ${data.results.length} feeds`)\n * }\n *\n * // Get feeds for a specific camera with streaming URLs\n * const { data: cameraFeeds } = await listFeeds({\n * deviceId: 'camera-123',\n * include: ['hlsUrl', 'multipartUrl']\n * })\n *\n * // Get preview feeds for multiple cameras\n * const { data: previewFeeds } = await listFeeds({\n * deviceId__in: ['camera-1', 'camera-2'],\n * type: 'preview',\n * include: ['hlsUrl']\n * })\n *\n * // Paginate through all feeds\n * let allFeeds: Feed[] = []\n * let pageToken: string | undefined\n * do {\n * const { data, error } = await listFeeds({ pageSize: 100, pageToken })\n * if (error) break\n * allFeeds.push(...data.results)\n * pageToken = data.nextPageToken\n * } while (pageToken)\n * ```\n *\n * @category Feeds\n */\nexport async function listFeeds(params?: ListFeedsParams): Promise<Result<ListFeedsResult>> {\n const authStore = useAuthStore()\n\n if (!authStore.isAuthenticated) {\n return failure('AUTH_REQUIRED', 'Authentication required')\n }\n\n if (!authStore.baseUrl) {\n return failure('AUTH_REQUIRED', 'Base URL not configured')\n }\n\n const queryParams = new URLSearchParams()\n\n // Pagination\n if (typeof params?.pageSize === 'number') {\n queryParams.append('pageSize', String(params.pageSize))\n }\n if (params?.pageToken) {\n queryParams.append('pageToken', params.pageToken)\n }\n\n // Device filters\n if (params?.deviceId) {\n queryParams.append('deviceId', params.deviceId)\n }\n if (params?.deviceId__in && params.deviceId__in.length > 0) {\n queryParams.append('deviceId__in', params.deviceId__in.join(','))\n }\n\n // Type filter\n if (params?.type) {\n queryParams.append('type', params.type)\n }\n\n // Include URL fields\n if (params?.include && params.include.length > 0) {\n queryParams.append('include', params.include.join(','))\n }\n\n const queryString = queryParams.toString()\n const url = `${authStore.baseUrl}/api/v3.0/feeds${queryString ? `?${queryString}` : ''}`\n debug('Fetching feeds:', url)\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n 'Accept': 'application/json',\n 'Authorization': `Bearer ${authStore.token}`\n },\n signal: params?.signal\n })\n\n if (!response.ok) {\n return handleErrorResponse(response)\n }\n\n const data = await response.json() as ListFeedsResult\n debug('Feeds fetched:', data.results?.length ?? 0, 'feeds')\n\n return success(data)\n } catch (err) {\n return failure('NETWORK_ERROR', `Failed to fetch feeds: ${String(err)}`)\n }\n}\n\n/**\n * Handle error responses from the API.\n * @internal\n */\nasync function handleErrorResponse<T>(response: Response): Promise<Result<T>> {\n const status = response.status\n\n let apiMessage: string | undefined\n try {\n const errorData = await response.json()\n apiMessage = errorData.message ?? errorData.error\n } catch (parseError) {\n debug('Failed to parse error response JSON:', parseError)\n }\n\n switch (status) {\n case 401:\n return failure('AUTH_REQUIRED', apiMessage || 'Authentication failed', status)\n case 403:\n return failure('FORBIDDEN', apiMessage || 'Access denied', status)\n case 404:\n return failure('NOT_FOUND', apiMessage || 'Not found', status)\n case 429:\n return failure('RATE_LIMITED', apiMessage || 'Rate limited', status)\n case 503:\n return failure('SERVICE_UNAVAILABLE', apiMessage || 'Service unavailable', status)\n default:\n return failure('API_ERROR', apiMessage || response.statusText || 'API error', status)\n }\n}\n","import { useAuthStore } from '../auth/store'\nimport { success, failure } from '../types'\nimport type {\n Result,\n PaginatedResult,\n Event,\n EventType,\n EventFieldValues,\n ListEventsParams,\n GetEventParams,\n ListEventTypesParams,\n ListEventFieldValuesParams\n} from '../types'\nimport { debug, formatTimestamp } from '../utils'\n\n/**\n * List events with required filters and optional pagination.\n *\n * @remarks\n * Fetches a paginated list of events from `/api/v3.0/events`. The `actor`,\n * `type__in`, and `startTimestamp__gte` parameters are required.\n *\n * For more details, see the\n * [EEN API Documentation](https://developer.eagleeyenetworks.com/reference/listevents).\n *\n * @param params - Required and optional filtering parameters\n * @returns A Result containing a paginated list of events or an error\n *\n * @example\n * ```typescript\n * import { listEvents } from 'een-api-toolkit'\n *\n * // Get motion events from a camera in the last hour\n * const { data, error } = await listEvents({\n * actor: 'camera:100d4c41',\n * type__in: ['een.motionDetectionEvent.v1'],\n * startTimestamp__gte: new Date(Date.now() - 3600000).toISOString()\n * })\n *\n * if (data) {\n * console.log(`Found ${data.results.length} events`)\n * data.results.forEach(event => {\n * console.log(`${event.type} at ${event.startTimestamp}`)\n * })\n * }\n *\n * // Fetch all events with pagination\n * let allEvents: Event[] = []\n * let pageToken: string | undefined\n * do {\n * const { data, error } = await listEvents({\n * actor: 'camera:100d4c41',\n * type__in: ['een.motionDetectionEvent.v1'],\n * startTimestamp__gte: new Date(Date.now() - 86400000).toISOString(),\n * pageSize: 100,\n * pageToken\n * })\n * if (error) break\n * allEvents.push(...data.results)\n * pageToken = data.nextPageToken\n * } while (pageToken)\n * ```\n *\n * @category Events\n */\nexport async function listEvents(params: ListEventsParams): Promise<Result<PaginatedResult<Event>>> {\n const authStore = useAuthStore()\n\n if (!authStore.isAuthenticated) {\n return failure('AUTH_REQUIRED', 'Authentication required')\n }\n\n if (!authStore.baseUrl) {\n return failure('AUTH_REQUIRED', 'Base URL not configured')\n }\n\n // Validate required parameters\n if (!params.actor) {\n return failure('VALIDATION_ERROR', 'actor parameter is required')\n }\n\n if (!params.type__in || params.type__in.length === 0) {\n return failure('VALIDATION_ERROR', 'type__in parameter is required and must not be empty')\n }\n\n if (!params.startTimestamp__gte) {\n return failure('VALIDATION_ERROR', 'startTimestamp__gte parameter is required')\n }\n\n const queryParams = new URLSearchParams()\n\n // Required filters\n queryParams.append('actor', params.actor)\n queryParams.append('type__in', params.type__in.join(','))\n queryParams.append('startTimestamp__gte', formatTimestamp(params.startTimestamp__gte))\n\n // Pagination\n if (params.pageSize) {\n queryParams.append('pageSize', String(params.pageSize))\n }\n if (params.pageToken) {\n queryParams.append('pageToken', params.pageToken)\n }\n\n // Optional time filters\n if (params.startTimestamp__lte) {\n queryParams.append('startTimestamp__lte', formatTimestamp(params.startTimestamp__lte))\n }\n if (params.endTimestamp__gte) {\n queryParams.append('endTimestamp__gte', formatTimestamp(params.endTimestamp__gte))\n }\n if (params.endTimestamp__lte) {\n queryParams.append('endTimestamp__lte', formatTimestamp(params.endTimestamp__lte))\n }\n\n // Sort\n if (params.sort) {\n queryParams.append('sort', params.sort)\n }\n\n // Include\n if (params.include && params.include.length > 0) {\n queryParams.append('include', params.include.join(','))\n }\n\n const queryString = queryParams.toString()\n const url = `${authStore.baseUrl}/api/v3.0/events${queryString ? `?${queryString}` : ''}`\n debug('Fetching events:', url)\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n 'Accept': 'application/json',\n 'Authorization': `Bearer ${authStore.token}`\n }\n })\n\n if (!response.ok) {\n return handleErrorResponse(response)\n }\n\n const data = await response.json() as PaginatedResult<Event>\n debug('Events fetched:', data.results?.length ?? 0, 'events')\n\n return success(data)\n } catch (err) {\n return failure('NETWORK_ERROR', `Failed to fetch events: ${String(err)}`)\n }\n}\n\n/**\n * Get a specific event by ID.\n *\n * @remarks\n * Fetches a single event from `/api/v3.0/events/{eventId}`. Use the `include`\n * parameter to request additional data schemas.\n *\n * For more details, see the\n * [EEN API Documentation](https://developer.eagleeyenetworks.com/reference/getevent).\n *\n * @param eventId - The unique identifier of the event to fetch\n * @param params - Optional parameters (e.g., include additional data schemas)\n * @returns A Result containing the event or an error\n *\n * @example\n * ```typescript\n * import { getEvent } from 'een-api-toolkit'\n *\n * const { data, error } = await getEvent('event-123')\n *\n * if (error) {\n * if (error.code === 'NOT_FOUND') {\n * console.log('Event not found')\n * }\n * return\n * }\n *\n * console.log(`Event: ${data.type} at ${data.startTimestamp}`)\n *\n * // With additional data schemas\n * const { data: eventWithData } = await getEvent('event-123', {\n * include: ['data.een.objectDetection.v1', 'data.een.fullFrameImageUrl.v1']\n * })\n * ```\n *\n * @category Events\n */\nexport async function getEvent(eventId: string, params?: GetEventParams): Promise<Result<Event>> {\n const authStore = useAuthStore()\n\n if (!authStore.isAuthenticated) {\n return failure('AUTH_REQUIRED', 'Authentication required')\n }\n\n if (!authStore.baseUrl) {\n return failure('AUTH_REQUIRED', 'Base URL not configured')\n }\n\n if (!eventId) {\n return failure('VALIDATION_ERROR', 'Event ID is required')\n }\n\n const queryParams = new URLSearchParams()\n\n if (params?.include && params.include.length > 0) {\n queryParams.append('include', params.include.join(','))\n }\n\n const queryString = queryParams.toString()\n const url = `${authStore.baseUrl}/api/v3.0/events/${encodeURIComponent(eventId)}${queryString ? `?${queryString}` : ''}`\n debug('Fetching event:', url)\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n 'Accept': 'application/json',\n 'Authorization': `Bearer ${authStore.token}`\n }\n })\n\n if (!response.ok) {\n return handleErrorResponse(response)\n }\n\n const data = await response.json() as Event\n debug('Event fetched:', data.id)\n\n return success(data)\n } catch (err) {\n return failure('NETWORK_ERROR', `Failed to fetch event: ${String(err)}`)\n }\n}\n\n/**\n * List all available event types.\n *\n * @remarks\n * Fetches a paginated list of event types from `/api/v3.0/eventTypes`. Event types\n * describe the different kinds of events that can be generated in the system.\n *\n * For more details, see the\n * [EEN API Documentation](https://developer.eagleeyenetworks.com/reference/listeventtypes).\n *\n * @param params - Optional pagination and language parameters\n * @returns A Result containing a paginated list of event types or an error\n *\n * @example\n * ```typescript\n * import { listEventTypes } from 'een-api-toolkit'\n *\n * const { data, error } = await listEventTypes()\n * if (data) {\n * data.results.forEach(eventType => {\n * console.log(`${eventType.name}: ${eventType.description}`)\n * })\n * }\n *\n * // With language parameter\n * const { data: localizedTypes } = await listEventTypes({ language: 'de' })\n * ```\n *\n * @category Events\n */\nexport async function listEventTypes(params?: ListEventTypesParams): Promise<Result<PaginatedResult<EventType>>> {\n const authStore = useAuthStore()\n\n if (!authStore.isAuthenticated) {\n return failure('AUTH_REQUIRED', 'Authentication required')\n }\n\n if (!authStore.baseUrl) {\n return failure('AUTH_REQUIRED', 'Base URL not configured')\n }\n\n const queryParams = new URLSearchParams()\n\n // Pagination\n if (params?.pageSize) {\n queryParams.append('pageSize', String(params.pageSize))\n }\n if (params?.pageToken) {\n queryParams.append('pageToken', params.pageToken)\n }\n\n // Language\n if (params?.language) {\n queryParams.append('language', params.language)\n }\n\n const queryString = queryParams.toString()\n const url = `${authStore.baseUrl}/api/v3.0/eventTypes${queryString ? `?${queryString}` : ''}`\n debug('Fetching event types:', url)\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n 'Accept': 'application/json',\n 'Authorization': `Bearer ${authStore.token}`\n }\n })\n\n if (!response.ok) {\n return handleErrorResponse(response)\n }\n\n const data = await response.json() as PaginatedResult<EventType>\n debug('Event types fetched:', data.results?.length ?? 0, 'types')\n\n return success(data)\n } catch (err) {\n return failure('NETWORK_ERROR', `Failed to fetch event types: ${String(err)}`)\n }\n}\n\n/**\n * List available event field values for a specific actor.\n *\n * @remarks\n * Fetches available event types for a specific actor from\n * `/api/v3.0/events:listFieldValues`. This is useful for building filter UIs\n * to know which event types are available for a camera or other device.\n *\n * For more details, see the\n * [EEN API Documentation](https://developer.eagleeyenetworks.com/reference/listeventfieldvalues).\n *\n * @param params - Parameters including the actor to query\n * @returns A Result containing available field values or an error\n *\n * @example\n * ```typescript\n * import { listEventFieldValues } from 'een-api-toolkit'\n *\n * const { data, error } = await listEventFieldValues({\n * actor: 'camera:100d4c41'\n * })\n *\n * if (data) {\n * console.log('Available event types:', data.type)\n * // Use these types to filter the listEvents call\n * }\n * ```\n *\n * @category Events\n */\nexport async function listEventFieldValues(params: ListEventFieldValuesParams): Promise<Result<EventFieldValues>> {\n const authStore = useAuthStore()\n\n if (!authStore.isAuthenticated) {\n return failure('AUTH_REQUIRED', 'Authentication required')\n }\n\n if (!authStore.baseUrl) {\n return failure('AUTH_REQUIRED', 'Base URL not configured')\n }\n\n // Validate required parameter\n if (!params.actor) {\n return failure('VALIDATION_ERROR', 'actor parameter is required')\n }\n\n const queryParams = new URLSearchParams()\n queryParams.append('actor', params.actor)\n\n const queryString = queryParams.toString()\n const url = `${authStore.baseUrl}/api/v3.0/events:listFieldValues${queryString ? `?${queryString}` : ''}`\n debug('Fetching event field values:', url)\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n 'Accept': 'application/json',\n 'Authorization': `Bearer ${authStore.token}`\n }\n })\n\n if (!response.ok) {\n return handleErrorResponse(response)\n }\n\n const data = await response.json() as EventFieldValues\n debug('Event field values fetched:', data.type?.length ?? 0, 'types')\n\n return success(data)\n } catch (err) {\n return failure('NETWORK_ERROR', `Failed to fetch event field values: ${String(err)}`)\n }\n}\n\n/**\n * Handle error responses from the API.\n * @internal\n */\nasync function handleErrorResponse<T>(response: Response): Promise<Result<T>> {\n const status = response.status\n\n let message: string\n try {\n const errorData = await response.json()\n message = errorData.message ?? errorData.error ?? response.statusText\n } catch (parseError) {\n debug('Failed to parse error response JSON:', parseError)\n message = response.statusText || 'Unknown error'\n }\n\n switch (status) {\n case 401:\n return failure('AUTH_REQUIRED', `Authentication failed: ${message}`, status)\n case 403:\n return failure('FORBIDDEN', `Access denied: ${message}`, status)\n case 404:\n return failure('NOT_FOUND', `Not found: ${message}`, status)\n case 429:\n return failure('RATE_LIMITED', `Rate limited: ${message}`, status)\n default:\n return failure('API_ERROR', `API error: ${message}`, status)\n }\n}\n","import { useAuthStore } from '../auth/store'\nimport { success, failure } from '../types'\nimport type {\n Result,\n EventMetric,\n GetEventMetricsParams\n} from '../types'\nimport { debug, formatTimestamp } from '../utils'\n\n/**\n * Get event metrics (time-series data) for a specific actor and event type.\n *\n * @remarks\n * Fetches time-series metric data from `/api/v3.0/eventMetrics`. The `actor` and\n * `eventType` parameters are required. Returns an array of EventMetric objects\n * containing data points over time.\n *\n * For more details, see the\n * [EEN API Documentation](https://developer.eagleeyenetworks.com/reference/listmetrics).\n *\n * @param params - Required and optional filtering parameters\n * @returns A Result containing an array of event metrics or an error\n *\n * @example\n * ```typescript\n * import { getEventMetrics } from 'een-api-toolkit'\n *\n * // Get motion event metrics for a camera (last 7 days by default)\n * const { data, error } = await getEventMetrics({\n * actor: 'camera:100d4c41',\n * eventType: 'een.motionDetectionEvent.v1'\n * })\n *\n * if (data) {\n * data.forEach(metric => {\n * console.log(`${metric.eventType}: ${metric.dataPoints.length} data points`)\n * metric.dataPoints.forEach(([timestamp, count]) => {\n * console.log(` ${new Date(timestamp).toISOString()}: ${count}`)\n * })\n * })\n * }\n *\n * // With custom time range and aggregation\n * const { data: hourlyData } = await getEventMetrics({\n * actor: 'camera:100d4c41',\n * eventType: 'een.motionDetectionEvent.v1',\n * timestamp__gte: new Date(Date.now() - 86400000).toISOString(),\n * timestamp__lte: new Date().toISOString(),\n * aggregateByMinutes: 60\n * })\n * ```\n *\n * @category Event Metrics\n */\nexport async function getEventMetrics(params: GetEventMetricsParams): Promise<Result<EventMetric[]>> {\n const authStore = useAuthStore()\n\n if (!authStore.isAuthenticated) {\n return failure('AUTH_REQUIRED', 'Authentication required')\n }\n\n if (!authStore.baseUrl) {\n return failure('AUTH_REQUIRED', 'Base URL not configured')\n }\n\n // Validate required parameters\n if (!params.actor) {\n return failure('VALIDATION_ERROR', 'actor parameter is required')\n }\n\n if (!params.eventType) {\n return failure('VALIDATION_ERROR', 'eventType parameter is required')\n }\n\n const queryParams = new URLSearchParams()\n\n // Required parameters\n queryParams.append('actor', params.actor)\n queryParams.append('eventType', params.eventType)\n\n // Optional time filters\n if (params.timestamp__gte) {\n queryParams.append('timestamp__gte', formatTimestamp(params.timestamp__gte))\n }\n if (params.timestamp__lte) {\n queryParams.append('timestamp__lte', formatTimestamp(params.timestamp__lte))\n }\n\n // Optional aggregation\n if (params.aggregateByMinutes !== undefined) {\n queryParams.append('aggregateByMinutes', String(params.aggregateByMinutes))\n }\n\n const queryString = queryParams.toString()\n const url = `${authStore.baseUrl}/api/v3.0/eventMetrics${queryString ? `?${queryString}` : ''}`\n debug('Fetching event metrics:', url)\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n 'Accept': 'application/json',\n 'Authorization': `Bearer ${authStore.token}`\n }\n })\n\n if (!response.ok) {\n return handleErrorResponse(response)\n }\n\n const data = await response.json() as EventMetric[]\n debug('Event metrics fetched:', data.length, 'metrics')\n\n return success(data)\n } catch (err) {\n return failure('NETWORK_ERROR', `Failed to fetch event metrics: ${String(err)}`)\n }\n}\n\n/**\n * Handle error responses from the API.\n * @internal\n */\nasync function handleErrorResponse<T>(response: Response): Promise<Result<T>> {\n const status = response.status\n\n let message: string\n try {\n const errorData = await response.json()\n message = errorData.message ?? errorData.error ?? response.statusText\n } catch (parseError) {\n debug('Failed to parse error response JSON:', parseError)\n message = response.statusText || 'Unknown error'\n }\n\n switch (status) {\n case 401:\n return failure('AUTH_REQUIRED', `Authentication failed: ${message}`, status)\n case 403:\n return failure('FORBIDDEN', `Access denied: ${message}`, status)\n case 404:\n return failure('NOT_FOUND', `Not found: ${message}`, status)\n case 429:\n return failure('RATE_LIMITED', `Rate limited: ${message}`, status)\n default:\n return failure('API_ERROR', `API error: ${message}`, status)\n }\n}\n","import { useAuthStore } from '../auth/store'\nimport { success, failure } from '../types'\nimport type {\n Result,\n PaginatedResult,\n Alert,\n AlertType,\n ListAlertsParams,\n GetAlertParams,\n ListAlertTypesParams\n} from '../types'\nimport { debug, formatTimestamp } from '../utils'\n\n/**\n * List alerts with optional filters and pagination.\n *\n * @remarks\n * Fetches a paginated list of alerts from `/api/v3.0/alerts`. Supports various\n * filters including time range, actor, alert type, priority, and more.\n *\n * For more details, see the\n * [EEN API Documentation](https://developer.eagleeyenetworks.com/reference/listalerts).\n *\n * @param params - Optional filtering and pagination parameters\n * @returns A Result containing a paginated list of alerts or an error\n *\n * @example\n * ```typescript\n * import { listAlerts } from 'een-api-toolkit'\n *\n * // Get recent alerts from a specific camera\n * const { data, error } = await listAlerts({\n * actorId__in: ['100d4c41'],\n * timestamp__gte: new Date(Date.now() - 3600000).toISOString(),\n * pageSize: 50,\n * include: ['data', 'actions']\n * })\n *\n * if (data) {\n * console.log(`Found ${data.results.length} alerts`)\n * data.results.forEach(alert => {\n * console.log(`${alert.alertType} at ${alert.timestamp}`)\n * })\n * }\n *\n * // Fetch all alerts with pagination\n * let allAlerts: Alert[] = []\n * let pageToken: string | undefined\n * do {\n * const { data, error } = await listAlerts({\n * timestamp__gte: new Date(Date.now() - 86400000).toISOString(),\n * pageSize: 100,\n * pageToken\n * })\n * if (error) break\n * allAlerts.push(...data.results)\n * pageToken = data.nextPageToken\n * } while (pageToken)\n * ```\n *\n * @category Alerts\n */\nexport async function listAlerts(params?: ListAlertsParams): Promise<Result<PaginatedResult<Alert>>> {\n const authStore = useAuthStore()\n\n if (!authStore.isAuthenticated) {\n return failure('AUTH_REQUIRED', 'Authentication required')\n }\n\n if (!authStore.baseUrl) {\n return failure('AUTH_REQUIRED', 'Base URL not configured')\n }\n\n const queryParams = new URLSearchParams()\n\n // Pagination\n if (params?.pageSize) {\n queryParams.append('pageSize', String(params.pageSize))\n }\n if (params?.pageToken) {\n queryParams.append('pageToken', params.pageToken)\n }\n\n // Time filters\n if (params?.timestamp__lte) {\n queryParams.append('timestamp__lte', formatTimestamp(params.timestamp__lte))\n }\n if (params?.timestamp__gte) {\n queryParams.append('timestamp__gte', formatTimestamp(params.timestamp__gte))\n }\n\n // Entity filters\n if (params?.creatorId) {\n queryParams.append('creatorId', params.creatorId)\n }\n if (params?.alertType__in && params.alertType__in.length > 0) {\n queryParams.append('alertType__in', params.alertType__in.join(','))\n }\n if (params?.actorId__in && params.actorId__in.length > 0) {\n queryParams.append('actorId__in', params.actorId__in.join(','))\n }\n if (params?.actorType__in && params.actorType__in.length > 0) {\n queryParams.append('actorType__in', params.actorType__in.join(','))\n }\n if (params?.actorAccountId) {\n queryParams.append('actorAccountId', params.actorAccountId)\n }\n\n // Rule filters\n if (params?.ruleId) {\n queryParams.append('ruleId', params.ruleId)\n }\n if (params?.ruleId__in && params.ruleId__in.length > 0) {\n queryParams.append('ruleId__in', params.ruleId__in.join(','))\n }\n\n // Event and location filters\n if (params?.eventId) {\n queryParams.append('eventId', params.eventId)\n }\n if (params?.locationId__in && params.locationId__in.length > 0) {\n queryParams.append('locationId__in', params.locationId__in.join(','))\n }\n\n // Priority filters\n if (params?.priority__gte !== undefined) {\n queryParams.append('priority__gte', String(params.priority__gte))\n }\n if (params?.priority__lte !== undefined) {\n queryParams.append('priority__lte', String(params.priority__lte))\n }\n\n // Other filters\n if (params?.showInvalidAlerts !== undefined) {\n queryParams.append('showInvalidAlerts', String(params.showInvalidAlerts))\n }\n if (params?.alertActionId__in && params.alertActionId__in.length > 0) {\n queryParams.append('alertActionId__in', params.alertActionId__in.join(','))\n }\n if (params?.alertActionStatus__in && params.alertActionStatus__in.length > 0) {\n queryParams.append('alertActionStatus__in', params.alertActionStatus__in.join(','))\n }\n\n // Response options\n if (params?.include && params.include.length > 0) {\n queryParams.append('include', params.include.join(','))\n }\n if (params?.sort && params.sort.length > 0) {\n queryParams.append('sort', params.sort.join(','))\n }\n if (params?.language) {\n queryParams.append('language', params.language)\n }\n\n const queryString = queryParams.toString()\n const url = `${authStore.baseUrl}/api/v3.0/alerts${queryString ? `?${queryString}` : ''}`\n debug('Fetching alerts:', url)\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n 'Accept': 'application/json',\n 'Authorization': `Bearer ${authStore.token}`\n }\n })\n\n if (!response.ok) {\n return handleErrorResponse(response)\n }\n\n const data = await response.json() as PaginatedResult<Alert>\n debug('Alerts fetched:', data.results?.length ?? 0, 'alerts')\n\n return success(data)\n } catch (err) {\n return failure('NETWORK_ERROR', `Failed to fetch alerts: ${String(err)}`)\n }\n}\n\n/**\n * Get a specific alert by ID.\n *\n * @remarks\n * Fetches a single alert from `/api/v3.0/alerts/{alertId}`. Use the `include`\n * parameter to request additional fields.\n *\n * For more details, see the\n * [EEN API Documentation](https://developer.eagleeyenetworks.com/reference/getalert).\n *\n * @param alertId - The unique identifier of the alert to fetch\n * @param params - Optional parameters (e.g., include additional fields)\n * @returns A Result containing the alert or an error\n *\n * @example\n * ```typescript\n * import { getAlert } from 'een-api-toolkit'\n *\n * const { data, error } = await getAlert('alert-123')\n *\n * if (error) {\n * if (error.code === 'NOT_FOUND') {\n * console.log('Alert not found')\n * }\n * return\n * }\n *\n * console.log(`Alert: ${data.alertType} at ${data.timestamp}`)\n *\n * // With additional fields\n * const { data: alertWithData } = await getAlert('alert-123', {\n * include: ['data', 'actions', 'description']\n * })\n * ```\n *\n * @category Alerts\n */\nexport async function getAlert(alertId: string, params?: GetAlertParams): Promise<Result<Alert>> {\n const authStore = useAuthStore()\n\n if (!authStore.isAuthenticated) {\n return failure('AUTH_REQUIRED', 'Authentication required')\n }\n\n if (!authStore.baseUrl) {\n return failure('AUTH_REQUIRED', 'Base URL not configured')\n }\n\n if (!alertId) {\n return failure('VALIDATION_ERROR', 'Alert ID is required')\n }\n\n const queryParams = new URLSearchParams()\n\n if (params?.include && params.include.length > 0) {\n queryParams.append('include', params.include.join(','))\n }\n\n const queryString = queryParams.toString()\n const url = `${authStore.baseUrl}/api/v3.0/alerts/${encodeURIComponent(alertId)}${queryString ? `?${queryString}` : ''}`\n debug('Fetching alert:', url)\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n 'Accept': 'application/json',\n 'Authorization': `Bearer ${authStore.token}`\n }\n })\n\n if (!response.ok) {\n return handleErrorResponse(response)\n }\n\n const data = await response.json() as Alert\n debug('Alert fetched:', data.id)\n\n return success(data)\n } catch (err) {\n return failure('NETWORK_ERROR', `Failed to fetch alert: ${String(err)}`)\n }\n}\n\n/**\n * List all available alert types.\n *\n * @remarks\n * Fetches a paginated list of alert types from `/api/v3.0/alertTypes`. Alert types\n * describe the different kinds of alerts that can be generated in the system.\n *\n * For more details, see the\n * [EEN API Documentation](https://developer.eagleeyenetworks.com/reference/listalerttypes).\n *\n * @param params - Optional pagination parameters\n * @returns A Result containing a paginated list of alert types or an error\n *\n * @example\n * ```typescript\n * import { listAlertTypes } from 'een-api-toolkit'\n *\n * const { data, error } = await listAlertTypes()\n * if (data) {\n * data.results.forEach(alertType => {\n * console.log(`${alertType.type}: ${alertType.description}`)\n * })\n * }\n *\n * // With pagination\n * const { data: pagedTypes } = await listAlertTypes({ pageSize: 20 })\n * ```\n *\n * @category Alerts\n */\nexport async function listAlertTypes(params?: ListAlertTypesParams): Promise<Result<PaginatedResult<AlertType>>> {\n const authStore = useAuthStore()\n\n if (!authStore.isAuthenticated) {\n return failure('AUTH_REQUIRED', 'Authentication required')\n }\n\n if (!authStore.baseUrl) {\n return failure('AUTH_REQUIRED', 'Base URL not configured')\n }\n\n const queryParams = new URLSearchParams()\n\n // Pagination\n if (params?.pageSize) {\n queryParams.append('pageSize', String(params.pageSize))\n }\n if (params?.pageToken) {\n queryParams.append('pageToken', params.pageToken)\n }\n\n const queryString = queryParams.toString()\n const url = `${authStore.baseUrl}/api/v3.0/alertTypes${queryString ? `?${queryString}` : ''}`\n debug('Fetching alert types:', url)\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n 'Accept': 'application/json',\n 'Authorization': `Bearer ${authStore.token}`\n }\n })\n\n if (!response.ok) {\n return handleErrorResponse(response)\n }\n\n const data = await response.json() as PaginatedResult<AlertType>\n debug('Alert types fetched:', data.results?.length ?? 0, 'types')\n\n return success(data)\n } catch (err) {\n return failure('NETWORK_ERROR', `Failed to fetch alert types: ${String(err)}`)\n }\n}\n\n/**\n * Handle error responses from the API.\n * @internal\n */\nasync function handleErrorResponse<T>(response: Response): Promise<Result<T>> {\n const status = response.status\n\n let message: string\n try {\n const errorData = await response.json()\n message = errorData.message ?? errorData.error ?? response.statusText\n } catch (parseError) {\n debug('Failed to parse error response JSON:', parseError)\n message = response.statusText || 'Unknown error'\n }\n\n switch (status) {\n case 401:\n return failure('AUTH_REQUIRED', `Authentication failed: ${message}`, status)\n case 403:\n return failure('FORBIDDEN', `Access denied: ${message}`, status)\n case 404:\n return failure('NOT_FOUND', `Not found: ${message}`, status)\n case 429:\n return failure('RATE_LIMITED', `Rate limited: ${message}`, status)\n default:\n return failure('API_ERROR', `API error: ${message}`, status)\n }\n}\n","import { useAuthStore } from '../auth/store'\nimport { success, failure } from '../types'\nimport type {\n Result,\n PaginatedResult,\n Notification,\n ListNotificationsParams\n} from '../types'\nimport { debug, formatTimestamp } from '../utils'\n\n/**\n * List notifications with optional filters and pagination.\n *\n * @remarks\n * Fetches a paginated list of notifications from `/api/v3.0/notifications`. Supports\n * various filters including time range, actor, alert type, category, and more.\n *\n * For more details, see the\n * [EEN API Documentation](https://developer.eagleeyenetworks.com/reference/listnotifications).\n *\n * @param params - Optional filtering and pagination parameters\n * @returns A Result containing a paginated list of notifications or an error\n *\n * @example\n * ```typescript\n * import { listNotifications } from 'een-api-toolkit'\n *\n * // Get recent notifications for a specific camera\n * const { data, error } = await listNotifications({\n * actorId: '100d4c41',\n * timestamp__gte: new Date(Date.now() - 3600000).toISOString(),\n * pageSize: 50\n * })\n *\n * if (data) {\n * console.log(`Found ${data.results.length} notifications`)\n * data.results.forEach(notification => {\n * console.log(`${notification.category}: ${notification.description}`)\n * })\n * }\n *\n * // Get unread notifications\n * const { data: unread } = await listNotifications({\n * read: false,\n * category: 'video'\n * })\n *\n * // Fetch all notifications with pagination\n * let allNotifications: Notification[] = []\n * let pageToken: string | undefined\n * do {\n * const { data, error } = await listNotifications({\n * timestamp__gte: new Date(Date.now() - 86400000).toISOString(),\n * pageSize: 100,\n * pageToken\n * })\n * if (error) break\n * allNotifications.push(...data.results)\n * pageToken = data.nextPageToken\n * } while (pageToken)\n * ```\n *\n * @category Notifications\n */\nexport async function listNotifications(params?: ListNotificationsParams): Promise<Result<PaginatedResult<Notification>>> {\n const authStore = useAuthStore()\n\n if (!authStore.isAuthenticated) {\n return failure('AUTH_REQUIRED', 'Authentication required')\n }\n\n if (!authStore.baseUrl) {\n return failure('AUTH_REQUIRED', 'Base URL not configured')\n }\n\n const queryParams = new URLSearchParams()\n\n // Pagination\n if (params?.pageSize) {\n queryParams.append('pageSize', String(params.pageSize))\n }\n if (params?.pageToken) {\n queryParams.append('pageToken', params.pageToken)\n }\n\n // Time filters\n if (params?.timestamp__lte) {\n queryParams.append('timestamp__lte', formatTimestamp(params.timestamp__lte))\n }\n if (params?.timestamp__gte) {\n queryParams.append('timestamp__gte', formatTimestamp(params.timestamp__gte))\n }\n\n // Entity filters\n if (params?.alertId) {\n queryParams.append('alertId', params.alertId)\n }\n if (params?.alertType) {\n queryParams.append('alertType', params.alertType)\n }\n if (params?.actorId) {\n queryParams.append('actorId', params.actorId)\n }\n if (params?.actorType) {\n queryParams.append('actorType', params.actorType)\n }\n if (params?.actorAccountId) {\n queryParams.append('actorAccountId', params.actorAccountId)\n }\n\n // Category and status filters\n if (params?.category) {\n queryParams.append('category', params.category)\n }\n if (params?.userId) {\n queryParams.append('userId', params.userId)\n }\n if (params?.read !== undefined) {\n queryParams.append('read', String(params.read))\n }\n if (params?.status) {\n queryParams.append('status', params.status)\n }\n\n // Other options\n if (params?.includeV1Notifications !== undefined) {\n queryParams.append('includeV1Notifications', String(params.includeV1Notifications))\n }\n\n // Response options\n if (params?.sort && params.sort.length > 0) {\n queryParams.append('sort', params.sort.join(','))\n }\n if (params?.language) {\n queryParams.append('language', params.language)\n }\n\n const queryString = queryParams.toString()\n const url = `${authStore.baseUrl}/api/v3.0/notifications${queryString ? `?${queryString}` : ''}`\n debug('Fetching notifications:', url)\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n 'Accept': 'application/json',\n 'Authorization': `Bearer ${authStore.token}`\n }\n })\n\n if (!response.ok) {\n return handleErrorResponse(response)\n }\n\n const data = await response.json() as PaginatedResult<Notification>\n debug('Notifications fetched:', data.results?.length ?? 0, 'notifications')\n\n return success(data)\n } catch (err) {\n return failure('NETWORK_ERROR', `Failed to fetch notifications: ${String(err)}`)\n }\n}\n\n/**\n * Get a specific notification by ID.\n *\n * @remarks\n * Fetches a single notification from `/api/v3.0/notifications/{notificationId}`.\n *\n * For more details, see the\n * [EEN API Documentation](https://developer.eagleeyenetworks.com/reference/getnotification).\n *\n * @param notificationId - The unique identifier of the notification to fetch\n * @returns A Result containing the notification or an error\n *\n * @example\n * ```typescript\n * import { getNotification } from 'een-api-toolkit'\n *\n * const { data, error } = await getNotification('notification-123')\n *\n * if (error) {\n * if (error.code === 'NOT_FOUND') {\n * console.log('Notification not found')\n * }\n * return\n * }\n *\n * console.log(`Notification: ${data.category} - ${data.description}`)\n * console.log(`Read: ${data.read}`)\n * ```\n *\n * @category Notifications\n */\nexport async function getNotification(notificationId: string): Promise<Result<Notification>> {\n const authStore = useAuthStore()\n\n if (!authStore.isAuthenticated) {\n return failure('AUTH_REQUIRED', 'Authentication required')\n }\n\n if (!authStore.baseUrl) {\n return failure('AUTH_REQUIRED', 'Base URL not configured')\n }\n\n if (!notificationId) {\n return failure('VALIDATION_ERROR', 'Notification ID is required')\n }\n\n const url = `${authStore.baseUrl}/api/v3.0/notifications/${encodeURIComponent(notificationId)}`\n debug('Fetching notification:', url)\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n 'Accept': 'application/json',\n 'Authorization': `Bearer ${authStore.token}`\n }\n })\n\n if (!response.ok) {\n return handleErrorResponse(response)\n }\n\n const data = await response.json() as Notification\n debug('Notification fetched:', data.id)\n\n return success(data)\n } catch (err) {\n return failure('NETWORK_ERROR', `Failed to fetch notification: ${String(err)}`)\n }\n}\n\n/**\n * Handle error responses from the API.\n * @internal\n */\nasync function handleErrorResponse<T>(response: Response): Promise<Result<T>> {\n const status = response.status\n\n let message: string\n try {\n const errorData = await response.json()\n message = errorData.message ?? errorData.error ?? response.statusText\n } catch (parseError) {\n debug('Failed to parse error response JSON:', parseError)\n message = response.statusText || 'Unknown error'\n }\n\n switch (status) {\n case 401:\n return failure('AUTH_REQUIRED', `Authentication failed: ${message}`, status)\n case 403:\n return failure('FORBIDDEN', `Access denied: ${message}`, status)\n case 404:\n return failure('NOT_FOUND', `Not found: ${message}`, status)\n case 429:\n return failure('RATE_LIMITED', `Rate limited: ${message}`, status)\n default:\n return failure('API_ERROR', `API error: ${message}`, status)\n }\n}\n"],"names":["isDebugEnabled","__vite_import_meta_env__","debug","args","STORAGE_STRATEGY_DESCRIPTIONS","MemoryStorage","key","value","BrowserStorageAdapter","storage","currentStrategy","memoryStorageInstance","getMemoryStorage","setStorageStrategy","strategy","getStorageStrategy","getStorageAdapter","config","initEenToolkit","options","storageStrategy","getConfig","getProxyUrl","getClientId","getRedirectUri","success","data","failure","code","message","status","details","formatTimestamp","timestamp","refreshTokenFnPromise","getRefreshTokenFn","service","useAuthStore","defineStore","token","ref","tokenExpiration","refreshTokenMarker","sessionId","hostname","port","userProfile","refreshTimerId","isRefreshing","refreshPromise","refreshFailed","refreshFailedMessage","isAuthenticated","computed","baseUrl","isTokenExpired","tokenExpiresIn","setToken","newToken","expiresIn","saveToStorage","setupAutoRefresh","setRefreshTokenMarker","marker","setSessionId","newSessionId","setBaseUrl","url","err","setUserProfile","profile","now","timeUntilExpiry","fiveMinutes","halfTtl","refreshBuffer","refreshTime","timeout","performAutoRefresh","result","clearRefreshFailed","logout","clearStorage","initialize","loadFromStorage","expStr","portStr","profileStr","EEN_AUTH_URL","getAuthUrl","clientId","state","params","getAccessToken","proxyUrl","response","errorText","refreshToken","authStore","headers","revokeToken","handleAuthCallback","storedState","constantTimeEquals","a","b","getCurrentUser","handleErrorResponse","getUsers","queryParams","queryString","getUser","userId","errorData","getCameras","getCamera","cameraId","parseError","getBridges","getBridge","bridgeId","DEFAULT_TIMEOUT_MS","createTimeoutController","timeoutMs","controller","timeoutId","arrayBufferToBase64","buffer","bytes","chunkSize","chunks","i","chunk","str","j","binary","listMedia","getLiveImage","type","prevToken","arrayBuffer","imageData","getRecordedImage","nextToken","overlaySvg","getMediaSession","initMediaSession","sessionResult","sessionUrl","listFeeds","apiMessage","listEvents","getEvent","eventId","listEventTypes","listEventFieldValues","getEventMetrics","listAlerts","getAlert","alertId","listAlertTypes","listNotifications","getNotification","notificationId"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","sources":["../src/utils/debug.ts","../src/utils/storage.ts","../src/config.ts","../src/types/common.ts","../src/utils/timestamp.ts","../src/auth/store.ts","../src/auth/service.ts","../src/users/service.ts","../src/cameras/service.ts","../src/bridges/service.ts","../src/media/service.ts","../src/feeds/service.ts","../src/events/service.ts","../src/eventMetrics/service.ts","../src/alerts/service.ts","../src/notifications/service.ts","../src/eventSubscriptions/service.ts"],"sourcesContent":["/**\n * Debug logging utility\n * Enabled when VITE_DEBUG=true in environment\n */\n\nconst isDebugEnabled = (): boolean => {\n try {\n return import.meta.env?.VITE_DEBUG === 'true'\n } catch {\n return false\n }\n}\n\nexport function debug(...args: unknown[]): void {\n if (isDebugEnabled()) {\n console.log('[een-api-toolkit]', ...args)\n }\n}\n\nexport function debugWarn(...args: unknown[]): void {\n if (isDebugEnabled()) {\n console.warn('[een-api-toolkit]', ...args)\n }\n}\n\nexport function debugError(...args: unknown[]): void {\n if (isDebugEnabled()) {\n console.error('[een-api-toolkit]', ...args)\n }\n}\n","// Import StorageStrategy from types to maintain single source of truth\nimport type { StorageStrategy } from '../types'\nimport { debug } from './debug'\n\n// Re-export for convenience\nexport type { StorageStrategy }\n\n/**\n * Human-readable descriptions for each storage strategy.\n * Useful for displaying storage information in UI components.\n *\n * @example\n * ```typescript\n * import { getStorageStrategy, STORAGE_STRATEGY_DESCRIPTIONS } from 'een-api-toolkit'\n *\n * const strategy = getStorageStrategy()\n * const description = STORAGE_STRATEGY_DESCRIPTIONS[strategy]\n * console.log(`Using ${strategy}: ${description}`)\n * ```\n *\n * @category Configuration\n */\nexport const STORAGE_STRATEGY_DESCRIPTIONS: Record<StorageStrategy, string> = {\n localStorage: 'persists across sessions',\n sessionStorage: 'per-tab, cleared on tab close',\n memory: 'tokens lost on page refresh'\n}\n\n/**\n * Storage adapter interface for token persistence.\n * @internal\n */\nexport interface StorageAdapter {\n getItem(key: string): string | null\n setItem(key: string, value: string): void\n removeItem(key: string): void\n}\n\n/**\n * In-memory storage implementation.\n * Tokens are lost on page refresh but are immune to storage-based XSS attacks.\n * @internal\n */\nclass MemoryStorage implements StorageAdapter {\n private store = new Map<string, string>()\n\n getItem(key: string): string | null {\n return this.store.get(key) ?? null\n }\n\n setItem(key: string, value: string): void {\n this.store.set(key, value)\n }\n\n removeItem(key: string): void {\n this.store.delete(key)\n }\n}\n\n/**\n * Browser storage wrapper that delegates to localStorage/sessionStorage.\n * Errors are propagated to the caller (auth/store.ts) for proper logging.\n * @internal\n */\nclass BrowserStorageAdapter implements StorageAdapter {\n constructor(private storage: Storage) {}\n\n getItem(key: string): string | null {\n return this.storage.getItem(key)\n }\n\n setItem(key: string, value: string): void {\n this.storage.setItem(key, value)\n }\n\n removeItem(key: string): void {\n this.storage.removeItem(key)\n }\n}\n\n// Singleton instances\nlet currentStrategy: StorageStrategy = 'localStorage'\nlet memoryStorageInstance: MemoryStorage | null = null\n\n/**\n * Get the memory storage singleton instance.\n * @internal\n */\nfunction getMemoryStorage(): MemoryStorage {\n if (!memoryStorageInstance) {\n memoryStorageInstance = new MemoryStorage()\n }\n return memoryStorageInstance\n}\n\n/**\n * Set the storage strategy for the toolkit.\n *\n * @param strategy - The storage strategy to use\n *\n * @remarks\n * This should be called during toolkit initialization via {@link initEenToolkit}.\n * Changing the strategy after authentication may cause the current session to be lost.\n *\n * @internal\n */\nexport function setStorageStrategy(strategy: StorageStrategy): void {\n currentStrategy = strategy\n}\n\n/**\n * Get the current storage strategy.\n *\n * @returns The currently configured storage strategy\n *\n * @category Configuration\n */\nexport function getStorageStrategy(): StorageStrategy {\n return currentStrategy\n}\n\n/**\n * Get the storage adapter for the current strategy.\n *\n * @returns A storage adapter implementation based on the configured strategy\n *\n * @internal\n */\nexport function getStorageAdapter(): StorageAdapter {\n switch (currentStrategy) {\n case 'memory':\n return getMemoryStorage()\n case 'sessionStorage':\n if (typeof sessionStorage !== 'undefined') {\n return new BrowserStorageAdapter(sessionStorage)\n }\n // Fallback to memory if sessionStorage not available\n debug('sessionStorage unavailable, falling back to memory storage')\n return getMemoryStorage()\n case 'localStorage':\n default:\n if (typeof localStorage !== 'undefined') {\n return new BrowserStorageAdapter(localStorage)\n }\n // Fallback to memory if localStorage not available\n debug('localStorage unavailable, falling back to memory storage')\n return getMemoryStorage()\n }\n}\n\n/**\n * Clear the memory storage instance.\n * Useful for testing or when switching strategies.\n *\n * @internal\n */\nexport function clearMemoryStorage(): void {\n memoryStorageInstance = null\n}\n","import type { EenToolkitConfig, StorageStrategy } from './types'\nimport { setStorageStrategy, getStorageStrategy, STORAGE_STRATEGY_DESCRIPTIONS } from './utils/storage'\n\n/**\n * Global toolkit configuration\n */\nlet config: EenToolkitConfig = {}\n\n/**\n * Initialize the EEN API Toolkit\n *\n * @remarks\n * Call this function once at application startup before using any toolkit features.\n * The storage strategy determines how authentication tokens are persisted.\n *\n * @param options - Configuration options for the toolkit\n *\n * @example\n * ```typescript\n * import { initEenToolkit } from 'een-api-toolkit'\n *\n * // Basic initialization with localStorage (default, backwards compatible)\n * initEenToolkit({\n * proxyUrl: 'https://your-proxy.workers.dev',\n * clientId: 'your-client-id'\n * })\n *\n * // High-security initialization with memory-only storage\n * initEenToolkit({\n * proxyUrl: 'https://your-proxy.workers.dev',\n * clientId: 'your-client-id',\n * storageStrategy: 'memory'\n * })\n * ```\n */\nexport function initEenToolkit(options: EenToolkitConfig = {}): void {\n // Set storage strategy first (default to localStorage for backwards compatibility)\n const storageStrategy: StorageStrategy = options.storageStrategy ?? 'localStorage'\n setStorageStrategy(storageStrategy)\n\n config = {\n proxyUrl: options.proxyUrl ?? import.meta.env?.VITE_PROXY_URL,\n clientId: options.clientId ?? import.meta.env?.VITE_EEN_CLIENT_ID,\n redirectUri: options.redirectUri ?? import.meta.env?.VITE_REDIRECT_URI,\n storageStrategy,\n debug: options.debug ?? import.meta.env?.VITE_DEBUG === 'true'\n }\n}\n\nexport { getStorageStrategy, STORAGE_STRATEGY_DESCRIPTIONS }\n\n/**\n * Get the current configuration\n */\nexport function getConfig(): EenToolkitConfig {\n return config\n}\n\n/**\n * Get the proxy URL\n */\nexport function getProxyUrl(): string | undefined {\n return config.proxyUrl ?? import.meta.env?.VITE_PROXY_URL\n}\n\n/**\n * Get the client ID\n */\nexport function getClientId(): string | undefined {\n return config.clientId ?? import.meta.env?.VITE_EEN_CLIENT_ID\n}\n\n/**\n * Get the redirect URI\n */\nexport function getRedirectUri(): string {\n return config.redirectUri ?? import.meta.env?.VITE_REDIRECT_URI ?? 'http://127.0.0.1:3333'\n}\n","/**\n * Error codes returned by the toolkit.\n *\n * @remarks\n * All API functions return a {@link Result} type that contains either data or an error.\n * The error code helps you determine how to handle the failure.\n *\n * @category Types\n */\nexport type ErrorCode =\n | 'AUTH_REQUIRED'\n | 'AUTH_FAILED'\n | 'TOKEN_EXPIRED'\n | 'API_ERROR'\n | 'NETWORK_ERROR'\n | 'VALIDATION_ERROR'\n | 'NOT_FOUND'\n | 'FORBIDDEN'\n | 'RATE_LIMITED'\n | 'SERVICE_UNAVAILABLE'\n | 'UNKNOWN_ERROR'\n\n/**\n * Error object returned when an operation fails.\n *\n * @remarks\n * Contains structured error information including a machine-readable code,\n * human-readable message, and optional HTTP status code.\n *\n * @example\n * ```typescript\n * const { error } = await getUsers()\n * if (error) {\n * console.error(`${error.code}: ${error.message}`)\n * if (error.status === 401) {\n * redirectToLogin()\n * }\n * }\n * ```\n *\n * @category Types\n */\nexport interface EenError {\n /** Machine-readable error code for programmatic handling */\n code: ErrorCode\n /** Human-readable error message */\n message: string\n /** HTTP status code if the error came from an API response */\n status?: number\n /** Additional error details (varies by error type) */\n details?: unknown\n}\n\n/**\n * Result type for all API operations - functions never throw exceptions.\n *\n * @remarks\n * This is a discriminated union type. When `error` is `null`, `data` contains\n * the successful result. When `error` is not `null`, `data` is `null`.\n * TypeScript will narrow the type correctly after checking for errors.\n *\n * @example\n * ```typescript\n * const { data, error } = await getUsers()\n *\n * if (error) {\n * // TypeScript knows: data is null, error is EenError\n * console.error(error.message)\n * return\n * }\n *\n * // TypeScript knows: data is not null, error is null\n * console.log(data.results)\n * ```\n *\n * @typeParam T - The type of the data on success\n * @category Types\n */\nexport type Result<T> =\n | { data: T; error: null }\n | { data: null; error: EenError }\n\n/**\n * Pagination parameters for list operations.\n *\n * @remarks\n * Most list APIs in the EEN platform support pagination. Use `pageSize` to\n * control how many results are returned, and `pageToken` to fetch subsequent pages.\n *\n * @example\n * ```typescript\n * // First page\n * const { data } = await getUsers({ pageSize: 50 })\n *\n * // Next page (if available)\n * if (data.nextPageToken) {\n * const { data: page2 } = await getUsers({\n * pageSize: 50,\n * pageToken: data.nextPageToken\n * })\n * }\n * ```\n *\n * @category Types\n */\nexport interface PaginationParams {\n /** Number of results per page (default varies by endpoint, typically 100) */\n pageSize?: number\n /** Token for fetching a specific page (from previous response's nextPageToken) */\n pageToken?: string\n}\n\n/**\n * Paginated response from list operations.\n *\n * @remarks\n * Contains the results array and optional pagination tokens for navigating\n * through large result sets.\n *\n * @typeParam T - The type of items in the results array\n * @category Types\n */\nexport interface PaginatedResult<T> {\n /** Array of items for this page */\n results: T[]\n /** Token to fetch the next page (undefined if no more pages) */\n nextPageToken?: string\n /** Token to fetch the previous page (undefined if on first page) */\n prevPageToken?: string\n /** Total number of items across all pages (may not be provided by all endpoints) */\n totalSize?: number\n}\n\n/**\n * Storage strategy options for token persistence.\n *\n * @remarks\n * Different storage strategies offer different security/convenience tradeoffs:\n *\n * - **localStorage**: Tokens persist across browser sessions. Most convenient but\n * vulnerable to XSS attacks since JavaScript can access localStorage.\n *\n * - **sessionStorage**: Tokens persist within a single tab session. Cleared when\n * the tab is closed. Each tab has isolated storage, so opening a new tab\n * requires re-authentication.\n *\n * - **memory**: Tokens are only kept in memory (Pinia store). Most secure as\n * tokens are never written to disk, but any page refresh requires re-authentication.\n *\n * @category Configuration\n */\nexport type StorageStrategy = 'localStorage' | 'sessionStorage' | 'memory'\n\n/**\n * Configuration for initializing the toolkit.\n *\n * @remarks\n * Pass this to {@link initEenToolkit} to configure the library. All options\n * can also be set via environment variables (VITE_PROXY_URL, VITE_EEN_CLIENT_ID,\n * VITE_REDIRECT_URI, VITE_DEBUG).\n *\n * @example\n * ```typescript\n * import { initEenToolkit } from 'een-api-toolkit'\n *\n * initEenToolkit({\n * proxyUrl: 'https://your-proxy.workers.dev',\n * clientId: 'your-een-client-id',\n * redirectUri: 'http://localhost:5173/callback',\n * storageStrategy: 'sessionStorage', // More secure than default\n * debug: true\n * })\n * ```\n *\n * @category Configuration\n */\nexport interface EenToolkitConfig {\n /** URL of the OAuth proxy server (required for API calls) */\n proxyUrl?: string\n /** EEN OAuth client ID (required for authentication) */\n clientId?: string\n /** OAuth redirect URI (default: http://127.0.0.1:3333) */\n redirectUri?: string\n /**\n * Storage strategy for token persistence (default: 'localStorage').\n *\n * Security vs convenience tradeoffs:\n * - 'localStorage': Persists across sessions, vulnerable to XSS\n * - 'sessionStorage': Per-tab isolation, cleared on tab close\n * - 'memory': Most secure, lost on page refresh\n */\n storageStrategy?: StorageStrategy\n /** Enable debug logging to console */\n debug?: boolean\n}\n\n/**\n * Helper to create a success result.\n *\n * @param data - The successful result data\n * @returns A Result object with data and null error\n *\n * @internal\n */\nexport function success<T>(data: T): Result<T> {\n return { data, error: null }\n}\n\n/**\n * Helper to create an error result.\n *\n * @param code - The error code\n * @param message - Human-readable error message\n * @param status - Optional HTTP status code\n * @param details - Optional additional error details\n * @returns A Result object with null data and error\n *\n * @internal\n */\nexport function failure<T>(code: ErrorCode, message: string, status?: number, details?: unknown): Result<T> {\n return { data: null, error: { code, message, status, details } }\n}\n","/**\n * Convert ISO 8601 timestamp from Z format to +00:00 format.\n *\n * @remarks\n * The EEN API requires timestamps in +00:00 format, not Z format.\n * This function converts timestamps like `2024-01-01T00:00:00.000Z`\n * to `2024-01-01T00:00:00.000+00:00`.\n *\n * @param timestamp - ISO 8601 timestamp string\n * @returns Timestamp in +00:00 format\n *\n * @example\n * ```typescript\n * formatTimestamp('2024-01-01T00:00:00.000Z')\n * // Returns: '2024-01-01T00:00:00.000+00:00'\n *\n * formatTimestamp(new Date().toISOString())\n * // Returns: timestamp with +00:00 suffix\n * ```\n *\n * @category Utilities\n */\nexport function formatTimestamp(timestamp: string): string {\n // If already in +00:00 format, return as-is\n if (timestamp.endsWith('+00:00')) {\n return timestamp\n }\n // Convert Z to +00:00\n if (timestamp.endsWith('Z')) {\n return timestamp.replace('Z', '+00:00')\n }\n // Return original if format is not recognized\n return timestamp\n}\n","import { defineStore } from 'pinia'\nimport { ref, computed } from 'vue'\nimport type { UserProfile } from '../types'\nimport type { Result } from '../types'\nimport { debug } from '../utils/debug'\nimport { getStorageAdapter } from '../utils/storage'\n\n// Lazy-loaded reference to refreshToken to avoid circular dependency at import time\n// Caches the promise (not the resolved value) to prevent race conditions with concurrent calls\nlet refreshTokenFnPromise: Promise<() => Promise<Result<{ accessToken: string; expiresIn: number }>>> | null = null\n\nfunction getRefreshTokenFn() {\n if (!refreshTokenFnPromise) {\n refreshTokenFnPromise = import('./service').then((service) => service.refreshToken)\n }\n return refreshTokenFnPromise\n}\n\n/**\n * Pinia store for authentication state management\n */\nexport const useAuthStore = defineStore('een-auth', () => {\n // State\n const token = ref<string | null>(null)\n const tokenExpiration = ref<number | null>(null)\n const refreshTokenMarker = ref<string | null>(null)\n const sessionId = ref<string | null>(null)\n const hostname = ref<string | null>(null)\n const port = ref<number>(443)\n const userProfile = ref<UserProfile | null>(null)\n const refreshTimerId = ref<ReturnType<typeof setTimeout> | null>(null)\n const isRefreshing = ref(false)\n let refreshPromise: Promise<void> | null = null\n const refreshFailed = ref(false)\n const refreshFailedMessage = ref<string | null>(null)\n\n // Computed\n const isAuthenticated = computed(() => !!token.value)\n\n const baseUrl = computed(() => {\n if (!hostname.value) return null\n return port.value === 443\n ? `https://${hostname.value}`\n : `https://${hostname.value}:${port.value}`\n })\n\n const isTokenExpired = computed(() => {\n if (!tokenExpiration.value) return true\n return Date.now() >= tokenExpiration.value\n })\n\n const tokenExpiresIn = computed(() => {\n if (!tokenExpiration.value) return 0\n return Math.max(0, tokenExpiration.value - Date.now())\n })\n\n // Actions\n function setToken(newToken: string, expiresIn: number) {\n token.value = newToken\n tokenExpiration.value = Date.now() + expiresIn * 1000\n saveToStorage()\n setupAutoRefresh()\n debug('Token set, expires in', expiresIn, 'seconds')\n }\n\n function setRefreshTokenMarker(marker: string) {\n refreshTokenMarker.value = marker\n saveToStorage()\n }\n\n function setSessionId(newSessionId: string) {\n sessionId.value = newSessionId\n saveToStorage()\n }\n\n function setBaseUrl(data: string | { hostname: string; port?: number }) {\n if (typeof data === 'string') {\n // Parse URL string\n try {\n const url = new URL(data.startsWith('http') ? data : `https://${data}`)\n hostname.value = url.hostname\n port.value = url.port ? parseInt(url.port, 10) : 443\n } catch (err: unknown) {\n // Invalid URL format, use as hostname directly\n debug('Failed to parse URL, using as hostname:', err instanceof Error ? err.message : String(err))\n hostname.value = data\n port.value = 443\n }\n } else {\n hostname.value = data.hostname\n port.value = data.port ?? 443\n }\n saveToStorage()\n debug('Base URL set:', baseUrl.value)\n }\n\n function setUserProfile(profile: UserProfile) {\n userProfile.value = profile\n saveToStorage()\n }\n\n function setupAutoRefresh() {\n // Clear existing timer\n if (refreshTimerId.value) {\n clearTimeout(refreshTimerId.value)\n refreshTimerId.value = null\n }\n\n if (!tokenExpiration.value || !token.value) {\n return\n }\n\n const now = Date.now()\n const expiresAt = tokenExpiration.value\n const timeUntilExpiry = expiresAt - now\n\n // Calculate refresh time: 5 minutes before expiration or 50% of TTL, whichever is earlier\n // Minimum: 1 minute before expiration, minimum timeout: 5 seconds\n const fiveMinutes = 5 * 60 * 1000\n const halfTtl = timeUntilExpiry / 2\n const refreshBuffer = Math.min(fiveMinutes, halfTtl)\n const refreshTime = Math.max(timeUntilExpiry - refreshBuffer, 60 * 1000)\n const timeout = Math.max(refreshTime, 5000)\n\n debug('Auto-refresh scheduled in', Math.round(timeout / 1000), 'seconds')\n\n refreshTimerId.value = setTimeout(async () => {\n await performAutoRefresh()\n }, timeout)\n }\n\n async function performAutoRefresh(): Promise<void> {\n // If refresh is already in progress, wait for the existing promise\n if (refreshPromise) {\n debug('Refresh already in progress, waiting for existing refresh')\n return refreshPromise\n }\n\n isRefreshing.value = true\n debug('Performing auto-refresh')\n\n refreshPromise = (async () => {\n try {\n const refreshToken = await getRefreshTokenFn()\n const result = await refreshToken()\n\n if (result.error) {\n refreshFailed.value = true\n refreshFailedMessage.value = result.error.message\n debug('Auto-refresh failed:', result.error.message)\n } else {\n refreshFailed.value = false\n refreshFailedMessage.value = null\n debug('Auto-refresh successful')\n }\n } catch (err: unknown) {\n refreshFailed.value = true\n refreshFailedMessage.value = err instanceof Error ? err.message : String(err)\n debug('Auto-refresh error:', err)\n } finally {\n isRefreshing.value = false\n refreshPromise = null\n }\n })()\n\n return refreshPromise\n }\n\n function clearRefreshFailed() {\n refreshFailed.value = false\n refreshFailedMessage.value = null\n }\n\n function logout() {\n // Clear timer\n if (refreshTimerId.value) {\n clearTimeout(refreshTimerId.value)\n refreshTimerId.value = null\n }\n\n // Clear state\n token.value = null\n tokenExpiration.value = null\n refreshTokenMarker.value = null\n sessionId.value = null\n hostname.value = null\n port.value = 443\n userProfile.value = null\n refreshFailed.value = false\n refreshFailedMessage.value = null\n\n // Clear storage\n clearStorage()\n debug('Logged out')\n }\n\n function initialize() {\n loadFromStorage()\n if (token.value && !isTokenExpired.value) {\n setupAutoRefresh()\n debug('Initialized from storage')\n } else if (token.value && isTokenExpired.value) {\n debug('Stored token expired, clearing')\n logout()\n }\n }\n\n // Storage helpers - use configured storage strategy\n function saveToStorage() {\n try {\n const storage = getStorageAdapter()\n if (token.value) storage.setItem('een_token', token.value)\n if (tokenExpiration.value) storage.setItem('een_tokenExpiration', String(tokenExpiration.value))\n if (refreshTokenMarker.value) storage.setItem('een_refreshTokenMarker', refreshTokenMarker.value)\n if (sessionId.value) storage.setItem('een_sessionId', sessionId.value)\n if (hostname.value) storage.setItem('een_hostname', hostname.value)\n if (port.value !== 443) storage.setItem('een_port', String(port.value))\n if (userProfile.value) storage.setItem('een_userProfile', JSON.stringify(userProfile.value))\n } catch (err: unknown) {\n // Storage might not be available (SSR, private browsing, etc.)\n debug('Failed to save to storage:', err instanceof Error ? err.message : String(err))\n }\n }\n\n function loadFromStorage() {\n try {\n const storage = getStorageAdapter()\n token.value = storage.getItem('een_token')\n const expStr = storage.getItem('een_tokenExpiration')\n tokenExpiration.value = expStr ? parseInt(expStr, 10) : null\n refreshTokenMarker.value = storage.getItem('een_refreshTokenMarker')\n sessionId.value = storage.getItem('een_sessionId')\n hostname.value = storage.getItem('een_hostname')\n const portStr = storage.getItem('een_port')\n port.value = portStr ? parseInt(portStr, 10) : 443\n const profileStr = storage.getItem('een_userProfile')\n userProfile.value = profileStr ? JSON.parse(profileStr) : null\n } catch (err: unknown) {\n // Storage might not be available (SSR, private browsing, etc.)\n debug('Failed to load from storage:', err instanceof Error ? err.message : String(err))\n }\n }\n\n function clearStorage() {\n try {\n const storage = getStorageAdapter()\n storage.removeItem('een_token')\n storage.removeItem('een_tokenExpiration')\n storage.removeItem('een_refreshTokenMarker')\n storage.removeItem('een_sessionId')\n storage.removeItem('een_hostname')\n storage.removeItem('een_port')\n storage.removeItem('een_userProfile')\n } catch (err: unknown) {\n // Storage might not be available (SSR, private browsing, etc.)\n debug('Failed to clear storage:', err instanceof Error ? err.message : String(err))\n }\n }\n\n return {\n // State\n token,\n tokenExpiration,\n refreshTokenMarker,\n sessionId,\n hostname,\n port,\n userProfile,\n isRefreshing,\n refreshFailed,\n refreshFailedMessage,\n\n // Computed\n isAuthenticated,\n baseUrl,\n isTokenExpired,\n tokenExpiresIn,\n\n // Actions\n setToken,\n setRefreshTokenMarker,\n setSessionId,\n setBaseUrl,\n setUserProfile,\n setupAutoRefresh,\n clearRefreshFailed,\n logout,\n initialize\n }\n})\n","import { useAuthStore } from './store'\nimport { getProxyUrl, getClientId, getRedirectUri } from '../config'\nimport { success, failure } from '../types'\nimport type { Result } from '../types'\nimport { debug } from '../utils/debug'\n\nconst EEN_AUTH_URL = 'https://auth.eagleeyenetworks.com/oauth2/authorize'\n\n/**\n * Token response from the OAuth proxy.\n *\n * @remarks\n * This is the response returned by the proxy's `/proxy/getAccessToken` endpoint\n * after successfully exchanging an authorization code for an access token.\n *\n * @category Authentication\n */\nexport interface TokenResponse {\n accessToken: string\n expiresIn: number\n httpsBaseUrl: string | { hostname: string; port?: number }\n userEmail: string\n sessionId: string\n}\n\n/**\n * Generate the OAuth authorization URL\n */\nexport function getAuthUrl(): string {\n const clientId = getClientId()\n if (!clientId) {\n throw new Error('Client ID not configured. Call initEenToolkit() or set VITE_EEN_CLIENT_ID')\n }\n\n // Generate and store state for CSRF protection\n const state = crypto.randomUUID()\n try {\n sessionStorage.setItem('een_oauth_state', state)\n } catch {\n // sessionStorage might not be available\n }\n\n const params = new URLSearchParams({\n client_id: clientId,\n response_type: 'code',\n scope: 'vms.all',\n redirect_uri: getRedirectUri(),\n state\n })\n\n debug('Generated auth URL with state:', state)\n return `${EEN_AUTH_URL}?${params.toString()}`\n}\n\n/**\n * Exchange authorization code for access token\n */\nexport async function getAccessToken(code: string): Promise<Result<TokenResponse>> {\n const proxyUrl = getProxyUrl()\n if (!proxyUrl) {\n return failure('AUTH_FAILED', 'Proxy URL not configured. Call initEenToolkit() or set VITE_PROXY_URL')\n }\n\n const params = new URLSearchParams({\n code,\n redirect_uri: getRedirectUri()\n })\n\n try {\n const response = await fetch(`${proxyUrl}/proxy/getAccessToken?${params.toString()}`, {\n method: 'POST',\n credentials: 'include',\n headers: {\n 'Accept': 'application/json'\n }\n })\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => 'Unknown error')\n return failure('AUTH_FAILED', `Token exchange failed: ${errorText}`, response.status)\n }\n\n const data = await response.json() as TokenResponse\n debug('Token received, expires in:', data.expiresIn)\n return success(data)\n } catch (err) {\n return failure('NETWORK_ERROR', `Failed to exchange code: ${String(err)}`)\n }\n}\n\n/**\n * Refresh the access token using stored refresh token\n */\nexport async function refreshToken(): Promise<Result<{ accessToken: string; expiresIn: number }>> {\n const proxyUrl = getProxyUrl()\n if (!proxyUrl) {\n return failure('AUTH_FAILED', 'Proxy URL not configured')\n }\n\n const authStore = useAuthStore()\n\n try {\n const headers: HeadersInit = {\n 'Accept': 'application/json'\n }\n\n // Add session ID header as fallback for environments where cookies don't work\n if (authStore.sessionId) {\n headers['Authorization'] = `Bearer ${authStore.sessionId}`\n }\n\n const response = await fetch(`${proxyUrl}/proxy/refreshAccessToken`, {\n method: 'POST',\n credentials: 'include',\n headers\n })\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => 'Unknown error')\n return failure('AUTH_FAILED', `Token refresh failed: ${errorText}`, response.status)\n }\n\n const data = await response.json() as { accessToken: string; expiresIn: number }\n\n // Update store with new token\n authStore.setToken(data.accessToken, data.expiresIn)\n\n debug('Token refreshed, expires in:', data.expiresIn)\n return success(data)\n } catch (err) {\n return failure('NETWORK_ERROR', `Failed to refresh token: ${String(err)}`)\n }\n}\n\n/**\n * Revoke the current token and logout\n */\nexport async function revokeToken(): Promise<Result<void>> {\n const proxyUrl = getProxyUrl()\n if (!proxyUrl) {\n return failure('AUTH_FAILED', 'Proxy URL not configured')\n }\n\n const authStore = useAuthStore()\n\n try {\n const headers: HeadersInit = {\n 'Accept': 'application/json'\n }\n\n if (authStore.sessionId) {\n headers['Authorization'] = `Bearer ${authStore.sessionId}`\n }\n\n const response = await fetch(`${proxyUrl}/proxy/revoke`, {\n method: 'POST',\n credentials: 'include',\n headers\n })\n\n // Logout regardless of response\n authStore.logout()\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => 'Unknown error')\n return failure('AUTH_FAILED', `Token revocation failed: ${errorText}`, response.status)\n }\n\n debug('Token revoked')\n return success(undefined)\n } catch (err) {\n // Still logout on error\n authStore.logout()\n return failure('NETWORK_ERROR', `Failed to revoke token: ${String(err)}`)\n }\n}\n\n/**\n * Handle OAuth callback - validates state and exchanges code for token\n */\nexport async function handleAuthCallback(code: string, state: string): Promise<Result<TokenResponse>> {\n // Validate state for CSRF protection\n let storedState: string | null = null\n try {\n storedState = sessionStorage.getItem('een_oauth_state')\n sessionStorage.removeItem('een_oauth_state')\n } catch {\n // sessionStorage might not be available\n }\n\n if (!storedState) {\n return failure('AUTH_FAILED', 'No OAuth state found. Please restart the login process.')\n }\n\n // Constant-time comparison to prevent timing attacks\n if (!constantTimeEquals(state, storedState)) {\n return failure('AUTH_FAILED', 'Invalid OAuth state. Possible CSRF attack.')\n }\n\n debug('State validated, exchanging code for token')\n\n // Exchange code for token\n const result = await getAccessToken(code)\n\n if (result.error) {\n return result\n }\n\n // Update auth store with received data\n const authStore = useAuthStore()\n const data = result.data\n\n authStore.setToken(data.accessToken, data.expiresIn)\n authStore.setRefreshTokenMarker('present')\n authStore.setSessionId(data.sessionId)\n authStore.setBaseUrl(data.httpsBaseUrl)\n\n debug('Auth callback complete, user:', data.userEmail)\n\n return success(data)\n}\n\n/**\n * Constant-time string comparison to prevent timing attacks\n */\nfunction constantTimeEquals(a: string, b: string): boolean {\n if (a.length !== b.length) {\n return false\n }\n\n let result = 0\n for (let i = 0; i < a.length; i++) {\n result |= a.charCodeAt(i) ^ b.charCodeAt(i)\n }\n\n return result === 0\n}\n","import { useAuthStore } from '../auth/store'\nimport { success, failure } from '../types'\nimport type { Result, PaginatedResult, User, UserProfile, ListUsersParams, GetUserParams } from '../types'\nimport { debug } from '../utils/debug'\n\n/**\n * Get the current authenticated user's profile.\n *\n * @remarks\n * Fetches the profile of the currently authenticated user from `/api/v3.0/users/self`.\n * The result is also stored in the auth store for easy access via `useAuthStore().userProfile`.\n *\n * @returns A Result containing the user profile or an error\n *\n * @example\n * ```typescript\n * import { getCurrentUser } from 'een-api-toolkit'\n *\n * const { data, error } = await getCurrentUser()\n *\n * if (error) {\n * if (error.code === 'AUTH_REQUIRED') {\n * router.push('/login')\n * }\n * return\n * }\n *\n * console.log(`Welcome, ${data.firstName} ${data.lastName}`)\n * ```\n *\n * @category Users\n */\nexport async function getCurrentUser(): Promise<Result<UserProfile>> {\n const authStore = useAuthStore()\n\n if (!authStore.isAuthenticated) {\n return failure('AUTH_REQUIRED', 'Authentication required')\n }\n\n if (!authStore.baseUrl) {\n return failure('AUTH_REQUIRED', 'Base URL not configured')\n }\n\n const url = `${authStore.baseUrl}/api/v3.0/users/self`\n debug('Fetching current user:', url)\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n 'Accept': 'application/json',\n 'Authorization': `Bearer ${authStore.token}`\n }\n })\n\n if (!response.ok) {\n return handleErrorResponse(response)\n }\n\n const data = await response.json() as UserProfile\n debug('Current user fetched:', data.email)\n\n // Update profile in store\n authStore.setUserProfile(data)\n\n return success(data)\n } catch (err) {\n return failure('NETWORK_ERROR', `Failed to fetch current user: ${String(err)}`)\n }\n}\n\n/**\n * List users with optional pagination and filtering.\n *\n * @remarks\n * Fetches a paginated list of users from `/api/v3.0/users`. Use the `pageSize`\n * parameter to control how many results are returned per page, and `pageToken`\n * to navigate to subsequent pages.\n *\n * For more details, see the\n * [EEN API Documentation](https://developer.eagleeyenetworks.com/reference/getusers).\n *\n * @param params - Optional pagination and filtering parameters\n * @returns A Result containing a paginated list of users or an error\n *\n * @example\n * ```typescript\n * import { getUsers } from 'een-api-toolkit'\n *\n * // Basic usage\n * const { data, error } = await getUsers()\n * if (data) {\n * console.log(`Found ${data.results.length} users`)\n * }\n *\n * // With pagination\n * const { data } = await getUsers({ pageSize: 50 })\n * if (data?.nextPageToken) {\n * const { data: page2 } = await getUsers({\n * pageSize: 50,\n * pageToken: data.nextPageToken\n * })\n * }\n *\n * // Fetch all users\n * let allUsers: User[] = []\n * let pageToken: string | undefined\n * do {\n * const { data, error } = await getUsers({ pageSize: 100, pageToken })\n * if (error) break\n * allUsers.push(...data.results)\n * pageToken = data.nextPageToken\n * } while (pageToken)\n * ```\n *\n * @category Users\n */\nexport async function getUsers(params?: ListUsersParams): Promise<Result<PaginatedResult<User>>> {\n const authStore = useAuthStore()\n\n if (!authStore.isAuthenticated) {\n return failure('AUTH_REQUIRED', 'Authentication required')\n }\n\n if (!authStore.baseUrl) {\n return failure('AUTH_REQUIRED', 'Base URL not configured')\n }\n\n const queryParams = new URLSearchParams()\n\n if (params?.pageSize) {\n queryParams.append('pageSize', String(params.pageSize))\n }\n if (params?.pageToken) {\n queryParams.append('pageToken', params.pageToken)\n }\n if (params?.include && params.include.length > 0) {\n queryParams.append('include', params.include.join(','))\n }\n\n const queryString = queryParams.toString()\n const url = `${authStore.baseUrl}/api/v3.0/users${queryString ? `?${queryString}` : ''}`\n debug('Fetching users:', url)\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n 'Accept': 'application/json',\n 'Authorization': `Bearer ${authStore.token}`\n }\n })\n\n if (!response.ok) {\n return handleErrorResponse(response)\n }\n\n const data = await response.json() as PaginatedResult<User>\n debug('Users fetched:', data.results?.length ?? 0, 'users')\n\n return success(data)\n } catch (err) {\n return failure('NETWORK_ERROR', `Failed to fetch users: ${String(err)}`)\n }\n}\n\n/**\n * Get a specific user by ID.\n *\n * @remarks\n * Fetches a single user from `/api/v3.0/users/{userId}`. Use the `include`\n * parameter to request additional fields like permissions.\n *\n * For more details, see the\n * [EEN API Documentation](https://developer.eagleeyenetworks.com/reference/getuser).\n *\n * @param userId - The unique identifier of the user to fetch\n * @param params - Optional parameters (e.g., include additional fields)\n * @returns A Result containing the user or an error\n *\n * @example\n * ```typescript\n * import { getUser } from 'een-api-toolkit'\n *\n * const { data, error } = await getUser('user-123')\n *\n * if (error) {\n * if (error.code === 'NOT_FOUND') {\n * console.log('User not found')\n * }\n * return\n * }\n *\n * console.log(`User: ${data.firstName} ${data.lastName}`)\n *\n * // With permissions\n * const { data: userWithPerms } = await getUser('user-123', {\n * include: ['permissions']\n * })\n * console.log('Permissions:', userWithPerms?.permissions)\n * ```\n *\n * @category Users\n */\nexport async function getUser(userId: string, params?: GetUserParams): Promise<Result<User>> {\n const authStore = useAuthStore()\n\n if (!authStore.isAuthenticated) {\n return failure('AUTH_REQUIRED', 'Authentication required')\n }\n\n if (!authStore.baseUrl) {\n return failure('AUTH_REQUIRED', 'Base URL not configured')\n }\n\n if (!userId) {\n return failure('VALIDATION_ERROR', 'User ID is required')\n }\n\n const queryParams = new URLSearchParams()\n\n if (params?.include && params.include.length > 0) {\n queryParams.append('include', params.include.join(','))\n }\n\n const queryString = queryParams.toString()\n const url = `${authStore.baseUrl}/api/v3.0/users/${encodeURIComponent(userId)}${queryString ? `?${queryString}` : ''}`\n debug('Fetching user:', url)\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n 'Accept': 'application/json',\n 'Authorization': `Bearer ${authStore.token}`\n }\n })\n\n if (!response.ok) {\n return handleErrorResponse(response)\n }\n\n const data = await response.json() as User\n debug('User fetched:', data.email)\n\n return success(data)\n } catch (err) {\n return failure('NETWORK_ERROR', `Failed to fetch user: ${String(err)}`)\n }\n}\n\n/**\n * Handle error responses from the API.\n * @internal\n */\nasync function handleErrorResponse<T>(response: Response): Promise<Result<T>> {\n const status = response.status\n\n let message: string\n try {\n const errorData = await response.json()\n message = errorData.message ?? errorData.error ?? response.statusText\n } catch {\n message = response.statusText || 'Unknown error'\n }\n\n switch (status) {\n case 401:\n return failure('AUTH_REQUIRED', `Authentication failed: ${message}`, status)\n case 403:\n return failure('FORBIDDEN', `Access denied: ${message}`, status)\n case 404:\n return failure('NOT_FOUND', `Not found: ${message}`, status)\n case 429:\n return failure('RATE_LIMITED', `Rate limited: ${message}`, status)\n default:\n return failure('API_ERROR', `API error: ${message}`, status)\n }\n}\n","import { useAuthStore } from '../auth/store'\nimport { success, failure } from '../types'\nimport type { Result, PaginatedResult, Camera, ListCamerasParams, GetCameraParams } from '../types'\nimport { debug } from '../utils/debug'\n\n/**\n * List cameras with optional pagination and filtering.\n *\n * @remarks\n * Fetches a paginated list of cameras from `/api/v3.0/cameras`. Supports\n * extensive filtering options for location, status, tags, and more.\n *\n * For more details, see the\n * [EEN API Documentation](https://developer.eagleeyenetworks.com/reference/listcameras).\n *\n * @param params - Optional pagination and filtering parameters\n * @returns A Result containing a paginated list of cameras or an error\n *\n * @example\n * ```typescript\n * import { getCameras } from 'een-api-toolkit'\n *\n * // Basic usage\n * const { data, error } = await getCameras()\n * if (data) {\n * console.log(`Found ${data.results.length} cameras`)\n * }\n *\n * // With filters\n * const { data } = await getCameras({\n * pageSize: 50,\n * status__in: ['online'],\n * include: ['deviceInfo', 'streamUrls']\n * })\n *\n * // Fetch all cameras\n * let allCameras: Camera[] = []\n * let pageToken: string | undefined\n * do {\n * const { data, error } = await getCameras({ pageSize: 100, pageToken })\n * if (error) break\n * allCameras.push(...data.results)\n * pageToken = data.nextPageToken\n * } while (pageToken)\n * ```\n *\n * @category Cameras\n */\nexport async function getCameras(params?: ListCamerasParams): Promise<Result<PaginatedResult<Camera>>> {\n const authStore = useAuthStore()\n\n if (!authStore.isAuthenticated) {\n return failure('AUTH_REQUIRED', 'Authentication required')\n }\n\n if (!authStore.baseUrl) {\n return failure('AUTH_REQUIRED', 'Base URL not configured')\n }\n\n const queryParams = new URLSearchParams()\n\n // Pagination\n if (params?.pageSize) {\n queryParams.append('pageSize', String(params.pageSize))\n }\n if (params?.pageToken) {\n queryParams.append('pageToken', params.pageToken)\n }\n\n // Include/Sort\n if (params?.include && params.include.length > 0) {\n queryParams.append('include', params.include.join(','))\n }\n if (params?.sort && params.sort.length > 0) {\n queryParams.append('sort', params.sort.join(','))\n }\n\n // Location/Bridge filters\n if (params?.locationId__in && params.locationId__in.length > 0) {\n queryParams.append('locationId__in', params.locationId__in.join(','))\n }\n if (params?.bridgeId__in && params.bridgeId__in.length > 0) {\n queryParams.append('bridgeId__in', params.bridgeId__in.join(','))\n }\n\n // Multi-camera filters\n if (params?.multiCameraId) {\n queryParams.append('multiCameraId', params.multiCameraId)\n }\n if (params?.multiCameraId__ne) {\n queryParams.append('multiCameraId__ne', params.multiCameraId__ne)\n }\n if (params?.multiCameraId__in && params.multiCameraId__in.length > 0) {\n queryParams.append('multiCameraId__in', params.multiCameraId__in.join(','))\n }\n\n // Tag/Package filters\n if (params?.tags__contains && params.tags__contains.length > 0) {\n queryParams.append('tags__contains', params.tags__contains.join(','))\n }\n if (params?.tags__any && params.tags__any.length > 0) {\n queryParams.append('tags__any', params.tags__any.join(','))\n }\n if (params?.packages__contains && params.packages__contains.length > 0) {\n queryParams.append('packages__contains', params.packages__contains.join(','))\n }\n\n // Name filters\n if (params?.name) {\n queryParams.append('name', params.name)\n }\n if (params?.name__contains) {\n queryParams.append('name__contains', params.name__contains)\n }\n if (params?.name__in && params.name__in.length > 0) {\n queryParams.append('name__in', params.name__in.join(','))\n }\n\n // ID filters\n if (params?.id__in && params.id__in.length > 0) {\n queryParams.append('id__in', params.id__in.join(','))\n }\n if (params?.id__notIn && params.id__notIn.length > 0) {\n queryParams.append('id__notIn', params.id__notIn.join(','))\n }\n if (params?.id__contains) {\n queryParams.append('id__contains', params.id__contains)\n }\n\n // Layout filter\n if (params?.layoutId) {\n queryParams.append('layoutId', params.layoutId)\n }\n\n // Share filters (use API nested field syntax)\n if (typeof params?.shared === 'boolean') {\n queryParams.append('shareDetails.shared', String(params.shared))\n }\n if (params?.sharedCameraAccount) {\n queryParams.append('shareDetails.accountId', params.sharedCameraAccount)\n }\n if (typeof params?.firstResponder === 'boolean') {\n queryParams.append('shareDetails.firstResponder', String(params.firstResponder))\n }\n\n // Device filters\n if (typeof params?.directToCloud === 'boolean') {\n queryParams.append('deviceInfo.directToCloud', String(params.directToCloud))\n }\n\n // Speaker filter\n if (params?.speakerId__in && params.speakerId__in.length > 0) {\n queryParams.append('speakerId__in', params.speakerId__in.join(','))\n }\n\n // Search\n if (params?.q) {\n queryParams.append('q', params.q)\n }\n if (typeof params?.qRelevance__gte === 'number') {\n queryParams.append('qRelevance__gte', String(params.qRelevance__gte))\n }\n\n // Analytics filter\n if (params?.enabledAnalytics__contains && params.enabledAnalytics__contains.length > 0) {\n queryParams.append('enabledAnalytics__contains', params.enabledAnalytics__contains.join(','))\n }\n\n // Status filters\n if (params?.status__in && params.status__in.length > 0) {\n queryParams.append('status__in', params.status__in.join(','))\n }\n if (params?.status__ne) {\n queryParams.append('status__ne', params.status__ne)\n }\n\n const queryString = queryParams.toString()\n const url = `${authStore.baseUrl}/api/v3.0/cameras${queryString ? `?${queryString}` : ''}`\n debug('Fetching cameras:', url)\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n 'Accept': 'application/json',\n 'Authorization': `Bearer ${authStore.token}`\n }\n })\n\n if (!response.ok) {\n return handleErrorResponse(response)\n }\n\n const data = await response.json() as PaginatedResult<Camera>\n debug('Cameras fetched:', data.results?.length ?? 0, 'cameras')\n\n return success(data)\n } catch (err) {\n return failure('NETWORK_ERROR', `Failed to fetch cameras: ${String(err)}`)\n }\n}\n\n/**\n * Get a specific camera by ID.\n *\n * @remarks\n * Fetches a single camera from `/api/v3.0/cameras/{cameraId}`. Use the `include`\n * parameter to request additional fields.\n *\n * For more details, see the\n * [EEN API Documentation](https://developer.eagleeyenetworks.com/reference/getcamera).\n *\n * @param cameraId - The unique identifier of the camera to fetch\n * @param params - Optional parameters (e.g., include additional fields)\n * @returns A Result containing the camera or an error\n *\n * @example\n * ```typescript\n * import { getCamera } from 'een-api-toolkit'\n *\n * const { data, error } = await getCamera('camera-123')\n *\n * if (error) {\n * if (error.code === 'NOT_FOUND') {\n * console.log('Camera not found')\n * }\n * return\n * }\n *\n * console.log(`Camera: ${data.name} (${data.status})`)\n *\n * // With additional fields\n * const { data: cameraWithDetails } = await getCamera('camera-123', {\n * include: ['deviceInfo', 'streamUrls', 'shareDetails']\n * })\n * ```\n *\n * @category Cameras\n */\nexport async function getCamera(cameraId: string, params?: GetCameraParams): Promise<Result<Camera>> {\n const authStore = useAuthStore()\n\n if (!authStore.isAuthenticated) {\n return failure('AUTH_REQUIRED', 'Authentication required')\n }\n\n if (!authStore.baseUrl) {\n return failure('AUTH_REQUIRED', 'Base URL not configured')\n }\n\n if (!cameraId) {\n return failure('VALIDATION_ERROR', 'Camera ID is required')\n }\n\n const queryParams = new URLSearchParams()\n\n if (params?.include && params.include.length > 0) {\n queryParams.append('include', params.include.join(','))\n }\n\n const queryString = queryParams.toString()\n const url = `${authStore.baseUrl}/api/v3.0/cameras/${encodeURIComponent(cameraId)}${queryString ? `?${queryString}` : ''}`\n debug('Fetching camera:', url)\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n 'Accept': 'application/json',\n 'Authorization': `Bearer ${authStore.token}`\n }\n })\n\n if (!response.ok) {\n return handleErrorResponse(response)\n }\n\n const data = await response.json() as Camera\n debug('Camera fetched:', data.name)\n\n return success(data)\n } catch (err) {\n return failure('NETWORK_ERROR', `Failed to fetch camera: ${String(err)}`)\n }\n}\n\n/**\n * Handle error responses from the API.\n * @internal\n */\nasync function handleErrorResponse<T>(response: Response): Promise<Result<T>> {\n const status = response.status\n\n let message: string\n try {\n const errorData = await response.json()\n message = errorData.message ?? errorData.error ?? response.statusText\n } catch (parseError) {\n debug('Failed to parse error response JSON:', parseError)\n message = response.statusText || 'Unknown error'\n }\n\n switch (status) {\n case 401:\n return failure('AUTH_REQUIRED', `Authentication failed: ${message}`, status)\n case 403:\n return failure('FORBIDDEN', `Access denied: ${message}`, status)\n case 404:\n return failure('NOT_FOUND', `Not found: ${message}`, status)\n case 429:\n return failure('RATE_LIMITED', `Rate limited: ${message}`, status)\n default:\n return failure('API_ERROR', `API error: ${message}`, status)\n }\n}\n","import { useAuthStore } from '../auth/store'\nimport { success, failure } from '../types'\nimport type { Result, PaginatedResult, Bridge, ListBridgesParams, GetBridgeParams } from '../types'\nimport { debug } from '../utils/debug'\n\n/**\n * List bridges with optional pagination and filtering.\n *\n * @remarks\n * Fetches a paginated list of bridges from `/api/v3.0/bridges`. Supports\n * filtering options for location, status, tags, and more.\n *\n * For more details, see the\n * [EEN API Documentation](https://developer.eagleeyenetworks.com/reference/listbridges).\n *\n * @param params - Optional pagination and filtering parameters\n * @returns A Result containing a paginated list of bridges or an error\n *\n * @example\n * ```typescript\n * import { getBridges } from 'een-api-toolkit'\n *\n * // Basic usage\n * const { data, error } = await getBridges()\n * if (data) {\n * console.log(`Found ${data.results.length} bridges`)\n * }\n *\n * // With filters\n * const { data } = await getBridges({\n * pageSize: 50,\n * status__in: ['online'],\n * include: ['deviceInfo', 'networkInfo']\n * })\n *\n * // Fetch all bridges\n * let allBridges: Bridge[] = []\n * let pageToken: string | undefined\n * do {\n * const { data, error } = await getBridges({ pageSize: 100, pageToken })\n * if (error) break\n * allBridges.push(...data.results)\n * pageToken = data.nextPageToken\n * } while (pageToken)\n * ```\n *\n * @category Bridges\n */\nexport async function getBridges(params?: ListBridgesParams): Promise<Result<PaginatedResult<Bridge>>> {\n const authStore = useAuthStore()\n\n if (!authStore.isAuthenticated) {\n return failure('AUTH_REQUIRED', 'Authentication required')\n }\n\n if (!authStore.baseUrl) {\n return failure('AUTH_REQUIRED', 'Base URL not configured')\n }\n\n const queryParams = new URLSearchParams()\n\n // Pagination\n if (params?.pageSize) {\n queryParams.append('pageSize', String(params.pageSize))\n }\n if (params?.pageToken) {\n queryParams.append('pageToken', params.pageToken)\n }\n\n // Include/Sort\n if (params?.include && params.include.length > 0) {\n queryParams.append('include', params.include.join(','))\n }\n if (params?.sort && params.sort.length > 0) {\n queryParams.append('sort', params.sort.join(','))\n }\n\n // Location filters\n if (params?.locationId__in && params.locationId__in.length > 0) {\n queryParams.append('locationId__in', params.locationId__in.join(','))\n }\n\n // Tag filters\n if (params?.tags__contains && params.tags__contains.length > 0) {\n queryParams.append('tags__contains', params.tags__contains.join(','))\n }\n if (params?.tags__any && params.tags__any.length > 0) {\n queryParams.append('tags__any', params.tags__any.join(','))\n }\n\n // Name filters\n if (params?.name) {\n queryParams.append('name', params.name)\n }\n if (params?.name__contains) {\n queryParams.append('name__contains', params.name__contains)\n }\n if (params?.name__in && params.name__in.length > 0) {\n queryParams.append('name__in', params.name__in.join(','))\n }\n\n // ID filters\n if (params?.id__in && params.id__in.length > 0) {\n queryParams.append('id__in', params.id__in.join(','))\n }\n if (params?.id__notIn && params.id__notIn.length > 0) {\n queryParams.append('id__notIn', params.id__notIn.join(','))\n }\n\n // Search\n if (params?.q) {\n queryParams.append('q', params.q)\n }\n if (typeof params?.qRelevance__gte === 'number') {\n queryParams.append('qRelevance__gte', String(params.qRelevance__gte))\n }\n\n // Status filters\n if (params?.status__in && params.status__in.length > 0) {\n queryParams.append('status__in', params.status__in.join(','))\n }\n if (params?.status__ne) {\n queryParams.append('status__ne', params.status__ne)\n }\n\n const queryString = queryParams.toString()\n const url = `${authStore.baseUrl}/api/v3.0/bridges${queryString ? `?${queryString}` : ''}`\n debug('Fetching bridges:', url)\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n 'Accept': 'application/json',\n 'Authorization': `Bearer ${authStore.token}`\n }\n })\n\n if (!response.ok) {\n return handleErrorResponse(response)\n }\n\n const data = await response.json() as PaginatedResult<Bridge>\n debug('Bridges fetched:', data.results?.length ?? 0, 'bridges')\n\n return success(data)\n } catch (err) {\n return failure('NETWORK_ERROR', `Failed to fetch bridges: ${String(err)}`)\n }\n}\n\n/**\n * Get a specific bridge by ID.\n *\n * @remarks\n * Fetches a single bridge from `/api/v3.0/bridges/{bridgeId}`. Use the `include`\n * parameter to request additional fields.\n *\n * For more details, see the\n * [EEN API Documentation](https://developer.eagleeyenetworks.com/reference/getbridge).\n *\n * @param bridgeId - The unique identifier of the bridge to fetch\n * @param params - Optional parameters (e.g., include additional fields)\n * @returns A Result containing the bridge or an error\n *\n * @example\n * ```typescript\n * import { getBridge } from 'een-api-toolkit'\n *\n * const { data, error } = await getBridge('bridge-123')\n *\n * if (error) {\n * if (error.code === 'NOT_FOUND') {\n * console.log('Bridge not found')\n * }\n * return\n * }\n *\n * console.log(`Bridge: ${data.name} (${data.status})`)\n *\n * // With additional fields\n * const { data: bridgeWithDetails } = await getBridge('bridge-123', {\n * include: ['deviceInfo', 'networkInfo', 'status']\n * })\n * ```\n *\n * @category Bridges\n */\nexport async function getBridge(bridgeId: string, params?: GetBridgeParams): Promise<Result<Bridge>> {\n const authStore = useAuthStore()\n\n if (!authStore.isAuthenticated) {\n return failure('AUTH_REQUIRED', 'Authentication required')\n }\n\n if (!authStore.baseUrl) {\n return failure('AUTH_REQUIRED', 'Base URL not configured')\n }\n\n if (!bridgeId) {\n return failure('VALIDATION_ERROR', 'Bridge ID is required')\n }\n\n const queryParams = new URLSearchParams()\n\n if (params?.include && params.include.length > 0) {\n queryParams.append('include', params.include.join(','))\n }\n\n const queryString = queryParams.toString()\n const url = `${authStore.baseUrl}/api/v3.0/bridges/${encodeURIComponent(bridgeId)}${queryString ? `?${queryString}` : ''}`\n debug('Fetching bridge:', url)\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n 'Accept': 'application/json',\n 'Authorization': `Bearer ${authStore.token}`\n }\n })\n\n if (!response.ok) {\n return handleErrorResponse(response)\n }\n\n const data = await response.json() as Bridge\n debug('Bridge fetched:', data.name)\n\n return success(data)\n } catch (err) {\n return failure('NETWORK_ERROR', `Failed to fetch bridge: ${String(err)}`)\n }\n}\n\n/**\n * Handle error responses from the API.\n * @internal\n */\nasync function handleErrorResponse<T>(response: Response): Promise<Result<T>> {\n const status = response.status\n\n let message: string\n try {\n const errorData = await response.json()\n message = errorData.message ?? errorData.error ?? response.statusText\n } catch (parseError) {\n debug('Failed to parse error response JSON:', parseError)\n message = response.statusText || 'Unknown error'\n }\n\n switch (status) {\n case 401:\n return failure('AUTH_REQUIRED', `Authentication failed: ${message}`, status)\n case 403:\n return failure('FORBIDDEN', `Access denied: ${message}`, status)\n case 404:\n return failure('NOT_FOUND', `Not found: ${message}`, status)\n case 429:\n return failure('RATE_LIMITED', `Rate limited: ${message}`, status)\n default:\n return failure('API_ERROR', `API error: ${message}`, status)\n }\n}\n","import { useAuthStore } from '../auth/store'\nimport { success, failure } from '../types'\nimport type {\n Result,\n PaginatedResult,\n MediaInterval,\n ListMediaParams,\n GetLiveImageParams,\n GetRecordedImageParams,\n LiveImageResult,\n RecordedImageResult,\n MediaSessionResponse,\n MediaSessionResult\n} from '../types'\nimport { debug } from '../utils/debug'\n\n/** Default timeout for media requests in milliseconds */\nconst DEFAULT_TIMEOUT_MS = 30000\n\n/**\n * Create an AbortController with a timeout.\n * @internal\n */\nfunction createTimeoutController(timeoutMs: number = DEFAULT_TIMEOUT_MS): { controller: AbortController; timeoutId: ReturnType<typeof setTimeout> } {\n const controller = new AbortController()\n const timeoutId = setTimeout(() => controller.abort(), timeoutMs)\n return { controller, timeoutId }\n}\n\n/**\n * Convert ArrayBuffer to base64 string.\n *\n * @remarks\n * **Memory Considerations**: This function loads the entire image into memory\n * as a string. For typical camera preview images (<500KB), this is efficient.\n * For larger images (>2MB), consider streaming or chunked processing in the\n * consuming application. Base64 encoding adds ~33% size overhead.\n *\n * @internal\n */\nfunction arrayBufferToBase64(buffer: ArrayBuffer): string {\n const bytes = new Uint8Array(buffer)\n // Use chunked approach with array join for O(n) complexity instead of O(n²) string concatenation\n // Iterate byte-by-byte within chunks to avoid call stack issues with String.fromCharCode.apply()\n const chunkSize = 8192\n const chunks: string[] = []\n for (let i = 0; i < bytes.byteLength; i += chunkSize) {\n const chunk = bytes.subarray(i, Math.min(i + chunkSize, bytes.byteLength))\n let str = ''\n for (let j = 0; j < chunk.length; j++) {\n str += String.fromCharCode(chunk[j]!)\n }\n chunks.push(str)\n }\n const binary = chunks.join('')\n // Use btoa in browser, Buffer in Node.js\n if (typeof btoa === 'function') {\n return btoa(binary)\n }\n return Buffer.from(binary, 'binary').toString('base64')\n}\n\n/**\n * List media intervals (recording periods) for a device.\n *\n * @remarks\n * Fetches a paginated list of time intervals for which recordings exist.\n * Use this to find available recordings for a camera.\n *\n * For more details, see the\n * [EEN API Documentation](https://developer.eagleeyenetworks.com/reference/listmedia).\n *\n * @param params - Required parameters including deviceId, type, mediaType, and startTimestamp\n * @returns A Result containing a paginated list of media intervals or an error\n *\n * @example\n * ```typescript\n * import { listMedia } from 'een-api-toolkit'\n *\n * // Get video recordings from the last hour\n * const { data, error } = await listMedia({\n * deviceId: 'camera-123',\n * type: 'preview',\n * mediaType: 'video',\n * startTimestamp: new Date(Date.now() - 3600000).toISOString()\n * })\n *\n * if (data) {\n * console.log(`Found ${data.results.length} recording intervals`)\n * data.results.forEach(interval => {\n * console.log(`${interval.startTimestamp} - ${interval.endTimestamp}`)\n * })\n * }\n * ```\n *\n * @category Media\n */\nexport async function listMedia(params: ListMediaParams): Promise<Result<PaginatedResult<MediaInterval>>> {\n const authStore = useAuthStore()\n\n if (!authStore.isAuthenticated) {\n return failure('AUTH_REQUIRED', 'Authentication required')\n }\n\n if (!authStore.baseUrl) {\n return failure('AUTH_REQUIRED', 'Base URL not configured')\n }\n\n // Validate required parameters\n if (!params.deviceId) {\n return failure('VALIDATION_ERROR', 'Device ID is required')\n }\n if (!params.type) {\n return failure('VALIDATION_ERROR', 'Stream type is required (preview or main)')\n }\n if (!params.mediaType) {\n return failure('VALIDATION_ERROR', 'Media type is required (video or image)')\n }\n if (!params.startTimestamp) {\n return failure('VALIDATION_ERROR', 'Start timestamp is required')\n }\n\n const queryParams = new URLSearchParams()\n\n // Required parameters\n queryParams.append('deviceId', params.deviceId)\n queryParams.append('type', params.type)\n queryParams.append('mediaType', params.mediaType)\n queryParams.append('startTimestamp__gte', params.startTimestamp)\n\n // Optional parameters\n if (params.endTimestamp) {\n queryParams.append('endTimestamp__lte', params.endTimestamp)\n }\n if (typeof params.coalesce === 'boolean') {\n queryParams.append('coalesce', String(params.coalesce))\n }\n if (params.include && params.include.length > 0) {\n queryParams.append('include', params.include.join(','))\n }\n if (params.pageToken) {\n queryParams.append('pageToken', params.pageToken)\n }\n if (typeof params.pageSize === 'number') {\n queryParams.append('pageSize', String(params.pageSize))\n }\n\n const url = `${authStore.baseUrl}/api/v3.0/media?${queryParams.toString()}`\n debug('Fetching media intervals:', url)\n\n const { controller, timeoutId } = createTimeoutController()\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n 'Accept': 'application/json',\n 'Authorization': `Bearer ${authStore.token}`\n },\n signal: controller.signal\n })\n\n if (!response.ok) {\n return handleErrorResponse(response)\n }\n\n const data = await response.json() as PaginatedResult<MediaInterval>\n debug('Media intervals fetched:', data.results?.length ?? 0, 'intervals')\n\n return success(data)\n } catch (err) {\n if (err instanceof Error && err.name === 'AbortError') {\n return failure('NETWORK_ERROR', 'Request timed out')\n }\n return failure('NETWORK_ERROR', `Failed to fetch media intervals: ${String(err)}`)\n } finally {\n clearTimeout(timeoutId)\n }\n}\n\n/**\n * Get a live image from a camera.\n *\n * @remarks\n * Fetches a new live image from the specified camera. This call waits until\n * a new image is available from the device. The image is returned as a\n * base64 data URL that can be used directly in an HTML img element.\n *\n * Note: Live images only support the 'preview' stream type.\n *\n * **Memory Considerations**: Images are loaded into memory and base64 encoded,\n * adding ~33% size overhead. Typical preview images are <500KB. For high-frequency\n * polling, consider implementing error backoff and limiting concurrent requests.\n *\n * For more details, see the\n * [EEN API Documentation](https://developer.eagleeyenetworks.com/reference/getliveimage).\n *\n * @param params - Parameters including the required deviceId\n * @returns A Result containing the live image data or an error\n *\n * @example\n * ```typescript\n * import { getLiveImage } from 'een-api-toolkit'\n *\n * const { data, error } = await getLiveImage({ deviceId: 'camera-123' })\n *\n * if (data) {\n * // Display in an img element\n * document.getElementById('cameraImage').src = data.imageData\n * console.log('Image timestamp:', data.timestamp)\n * }\n *\n * // Continuously update the image with proper error handling\n * let isRunning = true\n * async function refreshLoop() {\n * const imgElement = document.getElementById('cameraImage') as HTMLImageElement\n * while (isRunning) {\n * const { data, error } = await getLiveImage({ deviceId: 'camera-123' })\n * if (error) {\n * console.error('Refresh failed:', error.message)\n * break // Stop on error\n * }\n * if (data) {\n * imgElement.src = data.imageData\n * }\n * await new Promise(r => setTimeout(r, 1000))\n * }\n * }\n * // Call refreshLoop() to start, set isRunning = false to stop\n * ```\n *\n * @category Media\n */\nexport async function getLiveImage(params: GetLiveImageParams): Promise<Result<LiveImageResult>> {\n const authStore = useAuthStore()\n\n if (!authStore.isAuthenticated) {\n return failure('AUTH_REQUIRED', 'Authentication required')\n }\n\n if (!authStore.baseUrl) {\n return failure('AUTH_REQUIRED', 'Base URL not configured')\n }\n\n if (!params.deviceId) {\n return failure('VALIDATION_ERROR', 'Device ID is required')\n }\n\n // Live images only support 'preview' type (enforced by TypeScript)\n const type = params.type ?? 'preview'\n\n const queryParams = new URLSearchParams()\n queryParams.append('deviceId', params.deviceId)\n queryParams.append('type', type)\n\n const url = `${authStore.baseUrl}/api/v3.0/media/liveImage.jpeg?${queryParams.toString()}`\n debug('Fetching live image:', url)\n\n const { controller, timeoutId } = createTimeoutController()\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n 'Accept': 'image/jpeg',\n 'Authorization': `Bearer ${authStore.token}`\n },\n signal: controller.signal\n })\n\n // Get headers before checking response.ok\n const timestamp = response.headers.get('X-Een-Timestamp')\n const prevToken = response.headers.get('X-Een-PrevToken')\n\n if (!response.ok) {\n return handleErrorResponse(response)\n }\n\n // Get image as base64\n const arrayBuffer = await response.arrayBuffer()\n const base64 = arrayBufferToBase64(arrayBuffer)\n const imageData = `data:image/jpeg;base64,${base64}`\n\n debug('Live image fetched, timestamp:', timestamp)\n\n return success({\n imageData,\n timestamp,\n prevToken\n })\n } catch (err) {\n if (err instanceof Error && err.name === 'AbortError') {\n return failure('NETWORK_ERROR', 'Request timed out')\n }\n return failure('NETWORK_ERROR', `Failed to fetch live image: ${String(err)}`)\n } finally {\n clearTimeout(timeoutId)\n }\n}\n\n/**\n * Get a recorded image from a camera.\n *\n * @remarks\n * Fetches a recorded image from the specified camera at a specific timestamp.\n * You can specify the desired timestamp using various operators (exact, gte, lte, etc.)\n * or use a pageToken from a previous request to navigate through images.\n *\n * The image is returned as a base64 data URL that can be used directly in an HTML img element.\n *\n * Note: The 'main' type is rate-limited and requires an actual recording at the timestamp.\n *\n * For more details, see the\n * [EEN API Documentation](https://developer.eagleeyenetworks.com/reference/getrecordedimage).\n *\n * @param params - Parameters including deviceId/pageToken and timestamp options\n * @returns A Result containing the recorded image data or an error\n *\n * @example\n * ```typescript\n * import { getRecordedImage } from 'een-api-toolkit'\n *\n * // Get image at or after a specific time\n * const { data, error } = await getRecordedImage({\n * deviceId: 'camera-123',\n * type: 'preview',\n * timestamp__gte: '2024-01-15T10:00:00.000Z'\n * })\n *\n * if (data) {\n * imgElement.src = data.imageData\n * console.log('Actual timestamp:', data.timestamp)\n *\n * // Get the next image using the token\n * if (data.nextToken) {\n * const { data: nextImage } = await getRecordedImage({\n * pageToken: data.nextToken\n * })\n * }\n * }\n * ```\n *\n * @category Media\n */\nexport async function getRecordedImage(params: GetRecordedImageParams): Promise<Result<RecordedImageResult>> {\n const authStore = useAuthStore()\n\n if (!authStore.isAuthenticated) {\n return failure('AUTH_REQUIRED', 'Authentication required')\n }\n\n if (!authStore.baseUrl) {\n return failure('AUTH_REQUIRED', 'Base URL not configured')\n }\n\n // Validate: either deviceId or pageToken is required\n if (!params.deviceId && !params.pageToken) {\n return failure('VALIDATION_ERROR', 'Either deviceId or pageToken is required')\n }\n\n // If not using pageToken, validate at least one timestamp parameter\n if (!params.pageToken) {\n const hasTimestamp = params.timestamp__lt || params.timestamp__lte ||\n params.timestamp || params.timestamp__gte || params.timestamp__gt\n if (!hasTimestamp) {\n return failure('VALIDATION_ERROR', 'At least one timestamp parameter is required')\n }\n }\n\n // Validate overlay requirements\n if (params.include?.includes('overlaySvgHeader') &&\n (!params.overlayId__in || params.overlayId__in.length === 0)) {\n return failure('VALIDATION_ERROR', 'At least one overlayId must be provided when requesting overlay headers')\n }\n\n const queryParams = new URLSearchParams()\n\n // Add parameters\n if (params.deviceId) {\n queryParams.append('deviceId', params.deviceId)\n }\n if (params.pageToken) {\n queryParams.append('pageToken', params.pageToken)\n }\n if (params.type) {\n queryParams.append('type', params.type)\n }\n\n // Timestamp parameters\n if (params.timestamp__lt) {\n queryParams.append('timestamp__lt', params.timestamp__lt)\n }\n if (params.timestamp__lte) {\n queryParams.append('timestamp__lte', params.timestamp__lte)\n }\n if (params.timestamp) {\n queryParams.append('timestamp', params.timestamp)\n }\n if (params.timestamp__gte) {\n queryParams.append('timestamp__gte', params.timestamp__gte)\n }\n if (params.timestamp__gt) {\n queryParams.append('timestamp__gt', params.timestamp__gt)\n }\n\n // Overlay parameters\n if (params.overlayId__in && params.overlayId__in.length > 0) {\n queryParams.append('overlayId__in', params.overlayId__in.join(','))\n }\n if (params.include && params.include.length > 0) {\n queryParams.append('include', params.include.join(','))\n }\n\n // Size parameters\n if (typeof params.targetWidth === 'number') {\n queryParams.append('targetWidth', String(params.targetWidth))\n }\n if (typeof params.targetHeight === 'number') {\n queryParams.append('targetHeight', String(params.targetHeight))\n }\n\n const url = `${authStore.baseUrl}/api/v3.0/media/recordedImage.jpeg?${queryParams.toString()}`\n debug('Fetching recorded image:', url)\n\n const { controller, timeoutId } = createTimeoutController()\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n 'Accept': 'image/jpeg',\n 'Authorization': `Bearer ${authStore.token}`\n },\n signal: controller.signal\n })\n\n // Get headers before checking response.ok\n const timestamp = response.headers.get('X-Een-Timestamp')\n const nextToken = response.headers.get('X-Een-NextToken')\n const prevToken = response.headers.get('X-Een-PrevToken')\n const overlaySvg = response.headers.get('X-Een-OverlaySvg')\n\n if (!response.ok) {\n return handleErrorResponse(response)\n }\n\n // Get image as base64\n const arrayBuffer = await response.arrayBuffer()\n const base64 = arrayBufferToBase64(arrayBuffer)\n const imageData = `data:image/jpeg;base64,${base64}`\n\n debug('Recorded image fetched, timestamp:', timestamp)\n\n return success({\n imageData,\n timestamp,\n nextToken,\n prevToken,\n overlaySvg\n })\n } catch (err) {\n if (err instanceof Error && err.name === 'AbortError') {\n return failure('NETWORK_ERROR', 'Request timed out')\n }\n return failure('NETWORK_ERROR', `Failed to fetch recorded image: ${String(err)}`)\n } finally {\n clearTimeout(timeoutId)\n }\n}\n\n/**\n * Handle error responses from the API.\n * @internal\n */\nasync function handleErrorResponse<T>(response: Response): Promise<Result<T>> {\n const status = response.status\n\n let message: string\n try {\n const errorData = await response.json()\n message = errorData.message ?? errorData.error ?? response.statusText\n } catch {\n message = response.statusText || 'Unknown error'\n }\n\n switch (status) {\n case 401:\n return failure('AUTH_REQUIRED', `Authentication failed: ${message}`, status)\n case 403:\n return failure('FORBIDDEN', `Access denied: ${message}`, status)\n case 404:\n return failure('NOT_FOUND', `Not found: ${message}`, status)\n case 429:\n return failure('RATE_LIMITED', `Rate limited: ${message}`, status)\n case 503:\n return failure('SERVICE_UNAVAILABLE', `Service unavailable: ${message}`, status)\n default:\n return failure('API_ERROR', `API error: ${message}`, status)\n }\n}\n\n/**\n * Get the media session URL for setting cookies.\n *\n * @remarks\n * Fetches the URL needed to set the media session cookie. The returned URL\n * must be called separately (with credentials included) to actually set the\n * cookie. This is the first step in the two-step media session initialization\n * process.\n *\n * For most use cases, prefer using {@link initMediaSession} which handles\n * both steps automatically.\n *\n * For more details, see the\n * [EEN API Documentation](https://developer.eagleeyenetworks.com/docs/watch-live-video).\n *\n * @returns A Result containing the media session URL or an error\n *\n * @example\n * ```typescript\n * import { getMediaSession } from 'een-api-toolkit'\n *\n * // Get the session URL (step 1)\n * const { data, error } = await getMediaSession()\n *\n * if (data) {\n * console.log('Session URL:', data.url)\n * // Now call data.url with credentials: 'include' to set the cookie\n * }\n * ```\n *\n * @category Media\n */\nexport async function getMediaSession(): Promise<Result<MediaSessionResponse>> {\n const authStore = useAuthStore()\n\n if (!authStore.isAuthenticated) {\n return failure('AUTH_REQUIRED', 'Authentication required')\n }\n\n if (!authStore.baseUrl) {\n return failure('AUTH_REQUIRED', 'Base URL not configured')\n }\n\n const url = `${authStore.baseUrl}/api/v3.0/media/session`\n debug('Fetching media session:', url)\n\n const { controller, timeoutId } = createTimeoutController()\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n 'Accept': 'application/json',\n 'Authorization': `Bearer ${authStore.token}`\n },\n signal: controller.signal\n })\n\n if (!response.ok) {\n return handleErrorResponse(response)\n }\n\n const data = await response.json() as MediaSessionResponse\n debug('Media session URL received:', data.url)\n\n return success(data)\n } catch (err) {\n if (err instanceof Error && err.name === 'AbortError') {\n return failure('NETWORK_ERROR', 'Request timed out')\n }\n return failure('NETWORK_ERROR', `Failed to fetch media session: ${String(err)}`)\n } finally {\n clearTimeout(timeoutId)\n }\n}\n\n/**\n * Initialize the media session by setting the session cookie.\n *\n * @remarks\n * This function handles the two-step process of setting up a media session:\n * 1. Fetches the session URL from `/api/v3.0/media/session`\n * 2. Calls that URL with credentials to set the session cookie\n *\n * Once the session cookie is set, the browser can access media streams\n * (like multipart preview URLs) without explicit Authorization headers.\n * This is required for using media URLs directly in HTML elements like\n * `<img>` or `<video>`.\n *\n * **Important**: This function must be called in a browser environment\n * where cookies can be set. It uses `credentials: 'include'` to ensure\n * the cookie is stored.\n *\n * For more details, see the\n * [EEN API Documentation](https://developer.eagleeyenetworks.com/docs/watch-live-video).\n *\n * @returns A Result containing the session result or an error\n *\n * @example\n * ```typescript\n * import { initMediaSession, listFeeds } from 'een-api-toolkit'\n *\n * // Initialize the media session (do this once after login)\n * const { data, error } = await initMediaSession()\n *\n * if (error) {\n * console.error('Failed to init media session:', error.message)\n * return\n * }\n *\n * // Now you can use multipart URLs directly in <img> elements\n * const { data: feeds } = await listFeeds({\n * deviceId: 'camera-123',\n * include: ['multipartUrl']\n * })\n *\n * if (feeds?.results[0]?.multipartUrl) {\n * // This works because the session cookie is set\n * imgElement.src = feeds.results[0].multipartUrl\n * }\n * ```\n *\n * @category Media\n */\nexport async function initMediaSession(): Promise<Result<MediaSessionResult>> {\n const authStore = useAuthStore()\n\n if (!authStore.isAuthenticated) {\n return failure('AUTH_REQUIRED', 'Authentication required')\n }\n\n // Step 1: Get the media session URL\n const sessionResult = await getMediaSession()\n\n if (sessionResult.error) {\n return failure(\n sessionResult.error.code,\n `Failed to get media session: ${sessionResult.error.message}`,\n sessionResult.error.status\n )\n }\n\n if (!sessionResult.data?.url) {\n return failure('API_ERROR', 'No session URL returned from media session endpoint')\n }\n\n const sessionUrl = sessionResult.data.url\n debug('Calling session URL to set cookie:', sessionUrl)\n\n const { controller, timeoutId } = createTimeoutController()\n\n try {\n // Step 2: Call the session URL to set the cookie\n const response = await fetch(sessionUrl, {\n method: 'GET',\n credentials: 'include', // Critical: include cookies in the request/response\n headers: {\n 'Accept': '*/*',\n 'Authorization': `Bearer ${authStore.token}`\n },\n signal: controller.signal\n })\n\n // The session endpoint typically returns 204 No Content on success\n // but may also return 200 OK\n if (!response.ok && response.status !== 204) {\n const status = response.status\n\n let message: string\n try {\n const errorData = await response.json()\n message = errorData.message ?? errorData.error ?? response.statusText\n } catch {\n message = response.statusText || 'Unknown error'\n }\n\n return failure('API_ERROR', `Failed to set media session cookie: ${message}`, status)\n }\n\n debug('Media session cookie set successfully')\n\n return success({\n success: true,\n sessionUrl\n })\n } catch (err) {\n if (err instanceof Error && err.name === 'AbortError') {\n return failure('NETWORK_ERROR', 'Request timed out while setting session cookie')\n }\n return failure('NETWORK_ERROR', `Failed to set media session cookie: ${String(err)}`)\n } finally {\n clearTimeout(timeoutId)\n }\n}\n","import { useAuthStore } from '../auth/store'\nimport { success, failure } from '../types'\nimport type { Result, ListFeedsParams, ListFeedsResult } from '../types'\nimport { debug } from '../utils/debug'\n\n/**\n * List feeds with optional filtering and pagination.\n *\n * @remarks\n * Fetches a list of feeds from `/api/v3.0/feeds`. Feeds represent live or\n * recorded streams from devices (cameras, speakers). Use the `include` parameter\n * to request specific streaming URLs.\n *\n * A single device can have multiple feeds (main, preview, talkdown) with\n * different quality levels and purposes.\n *\n * For more details, see the\n * [EEN API Documentation](https://developer.eagleeyenetworks.com/reference/listfeeds).\n *\n * @param params - Optional filtering and pagination parameters\n * @returns A Result containing a list of feeds or an error\n *\n * @example\n * ```typescript\n * import { listFeeds } from 'een-api-toolkit'\n * import type { Feed } from 'een-api-toolkit'\n *\n * // Get all feeds\n * const { data, error } = await listFeeds()\n * if (data) {\n * console.log(`Found ${data.results.length} feeds`)\n * }\n *\n * // Get feeds for a specific camera with streaming URLs\n * const { data: cameraFeeds } = await listFeeds({\n * deviceId: 'camera-123',\n * include: ['hlsUrl', 'multipartUrl']\n * })\n *\n * // Get preview feeds for multiple cameras\n * const { data: previewFeeds } = await listFeeds({\n * deviceId__in: ['camera-1', 'camera-2'],\n * type: 'preview',\n * include: ['hlsUrl']\n * })\n *\n * // Paginate through all feeds\n * let allFeeds: Feed[] = []\n * let pageToken: string | undefined\n * do {\n * const { data, error } = await listFeeds({ pageSize: 100, pageToken })\n * if (error) break\n * allFeeds.push(...data.results)\n * pageToken = data.nextPageToken\n * } while (pageToken)\n * ```\n *\n * @category Feeds\n */\nexport async function listFeeds(params?: ListFeedsParams): Promise<Result<ListFeedsResult>> {\n const authStore = useAuthStore()\n\n if (!authStore.isAuthenticated) {\n return failure('AUTH_REQUIRED', 'Authentication required')\n }\n\n if (!authStore.baseUrl) {\n return failure('AUTH_REQUIRED', 'Base URL not configured')\n }\n\n const queryParams = new URLSearchParams()\n\n // Pagination\n if (typeof params?.pageSize === 'number') {\n queryParams.append('pageSize', String(params.pageSize))\n }\n if (params?.pageToken) {\n queryParams.append('pageToken', params.pageToken)\n }\n\n // Device filters\n if (params?.deviceId) {\n queryParams.append('deviceId', params.deviceId)\n }\n if (params?.deviceId__in && params.deviceId__in.length > 0) {\n queryParams.append('deviceId__in', params.deviceId__in.join(','))\n }\n\n // Type filter\n if (params?.type) {\n queryParams.append('type', params.type)\n }\n\n // Include URL fields\n if (params?.include && params.include.length > 0) {\n queryParams.append('include', params.include.join(','))\n }\n\n const queryString = queryParams.toString()\n const url = `${authStore.baseUrl}/api/v3.0/feeds${queryString ? `?${queryString}` : ''}`\n debug('Fetching feeds:', url)\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n 'Accept': 'application/json',\n 'Authorization': `Bearer ${authStore.token}`\n },\n signal: params?.signal\n })\n\n if (!response.ok) {\n return handleErrorResponse(response)\n }\n\n const data = await response.json() as ListFeedsResult\n debug('Feeds fetched:', data.results?.length ?? 0, 'feeds')\n\n return success(data)\n } catch (err) {\n return failure('NETWORK_ERROR', `Failed to fetch feeds: ${String(err)}`)\n }\n}\n\n/**\n * Handle error responses from the API.\n * @internal\n */\nasync function handleErrorResponse<T>(response: Response): Promise<Result<T>> {\n const status = response.status\n\n let apiMessage: string | undefined\n try {\n const errorData = await response.json()\n apiMessage = errorData.message ?? errorData.error\n } catch (parseError) {\n debug('Failed to parse error response JSON:', parseError)\n }\n\n switch (status) {\n case 401:\n return failure('AUTH_REQUIRED', apiMessage || 'Authentication failed', status)\n case 403:\n return failure('FORBIDDEN', apiMessage || 'Access denied', status)\n case 404:\n return failure('NOT_FOUND', apiMessage || 'Not found', status)\n case 429:\n return failure('RATE_LIMITED', apiMessage || 'Rate limited', status)\n case 503:\n return failure('SERVICE_UNAVAILABLE', apiMessage || 'Service unavailable', status)\n default:\n return failure('API_ERROR', apiMessage || response.statusText || 'API error', status)\n }\n}\n","import { useAuthStore } from '../auth/store'\nimport { success, failure } from '../types'\nimport type {\n Result,\n PaginatedResult,\n Event,\n EventType,\n EventFieldValues,\n ListEventsParams,\n GetEventParams,\n ListEventTypesParams,\n ListEventFieldValuesParams\n} from '../types'\nimport { debug, formatTimestamp } from '../utils'\n\n/**\n * List events with required filters and optional pagination.\n *\n * @remarks\n * Fetches a paginated list of events from `/api/v3.0/events`. The `actor`,\n * `type__in`, and `startTimestamp__gte` parameters are required.\n *\n * For more details, see the\n * [EEN API Documentation](https://developer.eagleeyenetworks.com/reference/listevents).\n *\n * @param params - Required and optional filtering parameters\n * @returns A Result containing a paginated list of events or an error\n *\n * @example\n * ```typescript\n * import { listEvents } from 'een-api-toolkit'\n *\n * // Get motion events from a camera in the last hour\n * const { data, error } = await listEvents({\n * actor: 'camera:100d4c41',\n * type__in: ['een.motionDetectionEvent.v1'],\n * startTimestamp__gte: new Date(Date.now() - 3600000).toISOString()\n * })\n *\n * if (data) {\n * console.log(`Found ${data.results.length} events`)\n * data.results.forEach(event => {\n * console.log(`${event.type} at ${event.startTimestamp}`)\n * })\n * }\n *\n * // Fetch all events with pagination\n * let allEvents: Event[] = []\n * let pageToken: string | undefined\n * do {\n * const { data, error } = await listEvents({\n * actor: 'camera:100d4c41',\n * type__in: ['een.motionDetectionEvent.v1'],\n * startTimestamp__gte: new Date(Date.now() - 86400000).toISOString(),\n * pageSize: 100,\n * pageToken\n * })\n * if (error) break\n * allEvents.push(...data.results)\n * pageToken = data.nextPageToken\n * } while (pageToken)\n * ```\n *\n * @category Events\n */\nexport async function listEvents(params: ListEventsParams): Promise<Result<PaginatedResult<Event>>> {\n const authStore = useAuthStore()\n\n if (!authStore.isAuthenticated) {\n return failure('AUTH_REQUIRED', 'Authentication required')\n }\n\n if (!authStore.baseUrl) {\n return failure('AUTH_REQUIRED', 'Base URL not configured')\n }\n\n // Validate required parameters\n if (!params.actor) {\n return failure('VALIDATION_ERROR', 'actor parameter is required')\n }\n\n if (!params.type__in || params.type__in.length === 0) {\n return failure('VALIDATION_ERROR', 'type__in parameter is required and must not be empty')\n }\n\n if (!params.startTimestamp__gte) {\n return failure('VALIDATION_ERROR', 'startTimestamp__gte parameter is required')\n }\n\n const queryParams = new URLSearchParams()\n\n // Required filters\n queryParams.append('actor', params.actor)\n queryParams.append('type__in', params.type__in.join(','))\n queryParams.append('startTimestamp__gte', formatTimestamp(params.startTimestamp__gte))\n\n // Pagination\n if (params.pageSize) {\n queryParams.append('pageSize', String(params.pageSize))\n }\n if (params.pageToken) {\n queryParams.append('pageToken', params.pageToken)\n }\n\n // Optional time filters\n if (params.startTimestamp__lte) {\n queryParams.append('startTimestamp__lte', formatTimestamp(params.startTimestamp__lte))\n }\n if (params.endTimestamp__gte) {\n queryParams.append('endTimestamp__gte', formatTimestamp(params.endTimestamp__gte))\n }\n if (params.endTimestamp__lte) {\n queryParams.append('endTimestamp__lte', formatTimestamp(params.endTimestamp__lte))\n }\n\n // Sort\n if (params.sort) {\n queryParams.append('sort', params.sort)\n }\n\n // Include\n if (params.include && params.include.length > 0) {\n queryParams.append('include', params.include.join(','))\n }\n\n const queryString = queryParams.toString()\n const url = `${authStore.baseUrl}/api/v3.0/events${queryString ? `?${queryString}` : ''}`\n debug('Fetching events:', url)\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n 'Accept': 'application/json',\n 'Authorization': `Bearer ${authStore.token}`\n }\n })\n\n if (!response.ok) {\n return handleErrorResponse(response)\n }\n\n const data = await response.json() as PaginatedResult<Event>\n debug('Events fetched:', data.results?.length ?? 0, 'events')\n\n return success(data)\n } catch (err) {\n return failure('NETWORK_ERROR', `Failed to fetch events: ${String(err)}`)\n }\n}\n\n/**\n * Get a specific event by ID.\n *\n * @remarks\n * Fetches a single event from `/api/v3.0/events/{eventId}`. Use the `include`\n * parameter to request additional data schemas.\n *\n * For more details, see the\n * [EEN API Documentation](https://developer.eagleeyenetworks.com/reference/getevent).\n *\n * @param eventId - The unique identifier of the event to fetch\n * @param params - Optional parameters (e.g., include additional data schemas)\n * @returns A Result containing the event or an error\n *\n * @example\n * ```typescript\n * import { getEvent } from 'een-api-toolkit'\n *\n * const { data, error } = await getEvent('event-123')\n *\n * if (error) {\n * if (error.code === 'NOT_FOUND') {\n * console.log('Event not found')\n * }\n * return\n * }\n *\n * console.log(`Event: ${data.type} at ${data.startTimestamp}`)\n *\n * // With additional data schemas\n * const { data: eventWithData } = await getEvent('event-123', {\n * include: ['data.een.objectDetection.v1', 'data.een.fullFrameImageUrl.v1']\n * })\n * ```\n *\n * @category Events\n */\nexport async function getEvent(eventId: string, params?: GetEventParams): Promise<Result<Event>> {\n const authStore = useAuthStore()\n\n if (!authStore.isAuthenticated) {\n return failure('AUTH_REQUIRED', 'Authentication required')\n }\n\n if (!authStore.baseUrl) {\n return failure('AUTH_REQUIRED', 'Base URL not configured')\n }\n\n if (!eventId) {\n return failure('VALIDATION_ERROR', 'Event ID is required')\n }\n\n const queryParams = new URLSearchParams()\n\n if (params?.include && params.include.length > 0) {\n queryParams.append('include', params.include.join(','))\n }\n\n const queryString = queryParams.toString()\n const url = `${authStore.baseUrl}/api/v3.0/events/${encodeURIComponent(eventId)}${queryString ? `?${queryString}` : ''}`\n debug('Fetching event:', url)\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n 'Accept': 'application/json',\n 'Authorization': `Bearer ${authStore.token}`\n }\n })\n\n if (!response.ok) {\n return handleErrorResponse(response)\n }\n\n const data = await response.json() as Event\n debug('Event fetched:', data.id)\n\n return success(data)\n } catch (err) {\n return failure('NETWORK_ERROR', `Failed to fetch event: ${String(err)}`)\n }\n}\n\n/**\n * List all available event types.\n *\n * @remarks\n * Fetches a paginated list of event types from `/api/v3.0/eventTypes`. Event types\n * describe the different kinds of events that can be generated in the system.\n *\n * For more details, see the\n * [EEN API Documentation](https://developer.eagleeyenetworks.com/reference/listeventtypes).\n *\n * @param params - Optional pagination and language parameters\n * @returns A Result containing a paginated list of event types or an error\n *\n * @example\n * ```typescript\n * import { listEventTypes } from 'een-api-toolkit'\n *\n * const { data, error } = await listEventTypes()\n * if (data) {\n * data.results.forEach(eventType => {\n * console.log(`${eventType.name}: ${eventType.description}`)\n * })\n * }\n *\n * // With language parameter\n * const { data: localizedTypes } = await listEventTypes({ language: 'de' })\n * ```\n *\n * @category Events\n */\nexport async function listEventTypes(params?: ListEventTypesParams): Promise<Result<PaginatedResult<EventType>>> {\n const authStore = useAuthStore()\n\n if (!authStore.isAuthenticated) {\n return failure('AUTH_REQUIRED', 'Authentication required')\n }\n\n if (!authStore.baseUrl) {\n return failure('AUTH_REQUIRED', 'Base URL not configured')\n }\n\n const queryParams = new URLSearchParams()\n\n // Pagination\n if (params?.pageSize) {\n queryParams.append('pageSize', String(params.pageSize))\n }\n if (params?.pageToken) {\n queryParams.append('pageToken', params.pageToken)\n }\n\n // Language\n if (params?.language) {\n queryParams.append('language', params.language)\n }\n\n const queryString = queryParams.toString()\n const url = `${authStore.baseUrl}/api/v3.0/eventTypes${queryString ? `?${queryString}` : ''}`\n debug('Fetching event types:', url)\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n 'Accept': 'application/json',\n 'Authorization': `Bearer ${authStore.token}`\n }\n })\n\n if (!response.ok) {\n return handleErrorResponse(response)\n }\n\n const data = await response.json() as PaginatedResult<EventType>\n debug('Event types fetched:', data.results?.length ?? 0, 'types')\n\n return success(data)\n } catch (err) {\n return failure('NETWORK_ERROR', `Failed to fetch event types: ${String(err)}`)\n }\n}\n\n/**\n * List available event field values for a specific actor.\n *\n * @remarks\n * Fetches available event types for a specific actor from\n * `/api/v3.0/events:listFieldValues`. This is useful for building filter UIs\n * to know which event types are available for a camera or other device.\n *\n * For more details, see the\n * [EEN API Documentation](https://developer.eagleeyenetworks.com/reference/listeventfieldvalues).\n *\n * @param params - Parameters including the actor to query\n * @returns A Result containing available field values or an error\n *\n * @example\n * ```typescript\n * import { listEventFieldValues } from 'een-api-toolkit'\n *\n * const { data, error } = await listEventFieldValues({\n * actor: 'camera:100d4c41'\n * })\n *\n * if (data) {\n * console.log('Available event types:', data.type)\n * // Use these types to filter the listEvents call\n * }\n * ```\n *\n * @category Events\n */\nexport async function listEventFieldValues(params: ListEventFieldValuesParams): Promise<Result<EventFieldValues>> {\n const authStore = useAuthStore()\n\n if (!authStore.isAuthenticated) {\n return failure('AUTH_REQUIRED', 'Authentication required')\n }\n\n if (!authStore.baseUrl) {\n return failure('AUTH_REQUIRED', 'Base URL not configured')\n }\n\n // Validate required parameter\n if (!params.actor) {\n return failure('VALIDATION_ERROR', 'actor parameter is required')\n }\n\n const queryParams = new URLSearchParams()\n queryParams.append('actor', params.actor)\n\n const queryString = queryParams.toString()\n const url = `${authStore.baseUrl}/api/v3.0/events:listFieldValues${queryString ? `?${queryString}` : ''}`\n debug('Fetching event field values:', url)\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n 'Accept': 'application/json',\n 'Authorization': `Bearer ${authStore.token}`\n }\n })\n\n if (!response.ok) {\n return handleErrorResponse(response)\n }\n\n const data = await response.json() as EventFieldValues\n debug('Event field values fetched:', data.type?.length ?? 0, 'types')\n\n return success(data)\n } catch (err) {\n return failure('NETWORK_ERROR', `Failed to fetch event field values: ${String(err)}`)\n }\n}\n\n/**\n * Handle error responses from the API.\n * @internal\n */\nasync function handleErrorResponse<T>(response: Response): Promise<Result<T>> {\n const status = response.status\n\n let message: string\n try {\n const errorData = await response.json()\n message = errorData.message ?? errorData.error ?? response.statusText\n } catch (parseError) {\n debug('Failed to parse error response JSON:', parseError)\n message = response.statusText || 'Unknown error'\n }\n\n switch (status) {\n case 401:\n return failure('AUTH_REQUIRED', `Authentication failed: ${message}`, status)\n case 403:\n return failure('FORBIDDEN', `Access denied: ${message}`, status)\n case 404:\n return failure('NOT_FOUND', `Not found: ${message}`, status)\n case 429:\n return failure('RATE_LIMITED', `Rate limited: ${message}`, status)\n default:\n return failure('API_ERROR', `API error: ${message}`, status)\n }\n}\n","import { useAuthStore } from '../auth/store'\nimport { success, failure } from '../types'\nimport type {\n Result,\n EventMetric,\n GetEventMetricsParams\n} from '../types'\nimport { debug, formatTimestamp } from '../utils'\n\n/**\n * Get event metrics (time-series data) for a specific actor and event type.\n *\n * @remarks\n * Fetches time-series metric data from `/api/v3.0/eventMetrics`. The `actor` and\n * `eventType` parameters are required. Returns an array of EventMetric objects\n * containing data points over time.\n *\n * For more details, see the\n * [EEN API Documentation](https://developer.eagleeyenetworks.com/reference/listmetrics).\n *\n * @param params - Required and optional filtering parameters\n * @returns A Result containing an array of event metrics or an error\n *\n * @example\n * ```typescript\n * import { getEventMetrics } from 'een-api-toolkit'\n *\n * // Get motion event metrics for a camera (last 7 days by default)\n * const { data, error } = await getEventMetrics({\n * actor: 'camera:100d4c41',\n * eventType: 'een.motionDetectionEvent.v1'\n * })\n *\n * if (data) {\n * data.forEach(metric => {\n * console.log(`${metric.eventType}: ${metric.dataPoints.length} data points`)\n * metric.dataPoints.forEach(([timestamp, count]) => {\n * console.log(` ${new Date(timestamp).toISOString()}: ${count}`)\n * })\n * })\n * }\n *\n * // With custom time range and aggregation\n * const { data: hourlyData } = await getEventMetrics({\n * actor: 'camera:100d4c41',\n * eventType: 'een.motionDetectionEvent.v1',\n * timestamp__gte: new Date(Date.now() - 86400000).toISOString(),\n * timestamp__lte: new Date().toISOString(),\n * aggregateByMinutes: 60\n * })\n * ```\n *\n * @category Event Metrics\n */\nexport async function getEventMetrics(params: GetEventMetricsParams): Promise<Result<EventMetric[]>> {\n const authStore = useAuthStore()\n\n if (!authStore.isAuthenticated) {\n return failure('AUTH_REQUIRED', 'Authentication required')\n }\n\n if (!authStore.baseUrl) {\n return failure('AUTH_REQUIRED', 'Base URL not configured')\n }\n\n // Validate required parameters\n if (!params.actor) {\n return failure('VALIDATION_ERROR', 'actor parameter is required')\n }\n\n if (!params.eventType) {\n return failure('VALIDATION_ERROR', 'eventType parameter is required')\n }\n\n const queryParams = new URLSearchParams()\n\n // Required parameters\n queryParams.append('actor', params.actor)\n queryParams.append('eventType', params.eventType)\n\n // Optional time filters\n if (params.timestamp__gte) {\n queryParams.append('timestamp__gte', formatTimestamp(params.timestamp__gte))\n }\n if (params.timestamp__lte) {\n queryParams.append('timestamp__lte', formatTimestamp(params.timestamp__lte))\n }\n\n // Optional aggregation\n if (params.aggregateByMinutes !== undefined) {\n queryParams.append('aggregateByMinutes', String(params.aggregateByMinutes))\n }\n\n const queryString = queryParams.toString()\n const url = `${authStore.baseUrl}/api/v3.0/eventMetrics${queryString ? `?${queryString}` : ''}`\n debug('Fetching event metrics:', url)\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n 'Accept': 'application/json',\n 'Authorization': `Bearer ${authStore.token}`\n }\n })\n\n if (!response.ok) {\n return handleErrorResponse(response)\n }\n\n const data = await response.json() as EventMetric[]\n debug('Event metrics fetched:', data.length, 'metrics')\n\n return success(data)\n } catch (err) {\n return failure('NETWORK_ERROR', `Failed to fetch event metrics: ${String(err)}`)\n }\n}\n\n/**\n * Handle error responses from the API.\n * @internal\n */\nasync function handleErrorResponse<T>(response: Response): Promise<Result<T>> {\n const status = response.status\n\n let message: string\n try {\n const errorData = await response.json()\n message = errorData.message ?? errorData.error ?? response.statusText\n } catch (parseError) {\n debug('Failed to parse error response JSON:', parseError)\n message = response.statusText || 'Unknown error'\n }\n\n switch (status) {\n case 401:\n return failure('AUTH_REQUIRED', `Authentication failed: ${message}`, status)\n case 403:\n return failure('FORBIDDEN', `Access denied: ${message}`, status)\n case 404:\n return failure('NOT_FOUND', `Not found: ${message}`, status)\n case 429:\n return failure('RATE_LIMITED', `Rate limited: ${message}`, status)\n default:\n return failure('API_ERROR', `API error: ${message}`, status)\n }\n}\n","import { useAuthStore } from '../auth/store'\nimport { success, failure } from '../types'\nimport type {\n Result,\n PaginatedResult,\n Alert,\n AlertType,\n ListAlertsParams,\n GetAlertParams,\n ListAlertTypesParams\n} from '../types'\nimport { debug, formatTimestamp } from '../utils'\n\n/**\n * List alerts with optional filters and pagination.\n *\n * @remarks\n * Fetches a paginated list of alerts from `/api/v3.0/alerts`. Supports various\n * filters including time range, actor, alert type, priority, and more.\n *\n * For more details, see the\n * [EEN API Documentation](https://developer.eagleeyenetworks.com/reference/listalerts).\n *\n * @param params - Optional filtering and pagination parameters\n * @returns A Result containing a paginated list of alerts or an error\n *\n * @example\n * ```typescript\n * import { listAlerts } from 'een-api-toolkit'\n *\n * // Get recent alerts from a specific camera\n * const { data, error } = await listAlerts({\n * actorId__in: ['100d4c41'],\n * timestamp__gte: new Date(Date.now() - 3600000).toISOString(),\n * pageSize: 50,\n * include: ['data', 'actions']\n * })\n *\n * if (data) {\n * console.log(`Found ${data.results.length} alerts`)\n * data.results.forEach(alert => {\n * console.log(`${alert.alertType} at ${alert.timestamp}`)\n * })\n * }\n *\n * // Fetch all alerts with pagination\n * let allAlerts: Alert[] = []\n * let pageToken: string | undefined\n * do {\n * const { data, error } = await listAlerts({\n * timestamp__gte: new Date(Date.now() - 86400000).toISOString(),\n * pageSize: 100,\n * pageToken\n * })\n * if (error) break\n * allAlerts.push(...data.results)\n * pageToken = data.nextPageToken\n * } while (pageToken)\n * ```\n *\n * @category Alerts\n */\nexport async function listAlerts(params?: ListAlertsParams): Promise<Result<PaginatedResult<Alert>>> {\n const authStore = useAuthStore()\n\n if (!authStore.isAuthenticated) {\n return failure('AUTH_REQUIRED', 'Authentication required')\n }\n\n if (!authStore.baseUrl) {\n return failure('AUTH_REQUIRED', 'Base URL not configured')\n }\n\n const queryParams = new URLSearchParams()\n\n // Pagination\n if (params?.pageSize) {\n queryParams.append('pageSize', String(params.pageSize))\n }\n if (params?.pageToken) {\n queryParams.append('pageToken', params.pageToken)\n }\n\n // Time filters\n if (params?.timestamp__lte) {\n queryParams.append('timestamp__lte', formatTimestamp(params.timestamp__lte))\n }\n if (params?.timestamp__gte) {\n queryParams.append('timestamp__gte', formatTimestamp(params.timestamp__gte))\n }\n\n // Entity filters\n if (params?.creatorId) {\n queryParams.append('creatorId', params.creatorId)\n }\n if (params?.alertType__in && params.alertType__in.length > 0) {\n queryParams.append('alertType__in', params.alertType__in.join(','))\n }\n if (params?.actorId__in && params.actorId__in.length > 0) {\n queryParams.append('actorId__in', params.actorId__in.join(','))\n }\n if (params?.actorType__in && params.actorType__in.length > 0) {\n queryParams.append('actorType__in', params.actorType__in.join(','))\n }\n if (params?.actorAccountId) {\n queryParams.append('actorAccountId', params.actorAccountId)\n }\n\n // Rule filters\n if (params?.ruleId) {\n queryParams.append('ruleId', params.ruleId)\n }\n if (params?.ruleId__in && params.ruleId__in.length > 0) {\n queryParams.append('ruleId__in', params.ruleId__in.join(','))\n }\n\n // Event and location filters\n if (params?.eventId) {\n queryParams.append('eventId', params.eventId)\n }\n if (params?.locationId__in && params.locationId__in.length > 0) {\n queryParams.append('locationId__in', params.locationId__in.join(','))\n }\n\n // Priority filters\n if (params?.priority__gte !== undefined) {\n queryParams.append('priority__gte', String(params.priority__gte))\n }\n if (params?.priority__lte !== undefined) {\n queryParams.append('priority__lte', String(params.priority__lte))\n }\n\n // Other filters\n if (params?.showInvalidAlerts !== undefined) {\n queryParams.append('showInvalidAlerts', String(params.showInvalidAlerts))\n }\n if (params?.alertActionId__in && params.alertActionId__in.length > 0) {\n queryParams.append('alertActionId__in', params.alertActionId__in.join(','))\n }\n if (params?.alertActionStatus__in && params.alertActionStatus__in.length > 0) {\n queryParams.append('alertActionStatus__in', params.alertActionStatus__in.join(','))\n }\n\n // Response options\n if (params?.include && params.include.length > 0) {\n queryParams.append('include', params.include.join(','))\n }\n if (params?.sort && params.sort.length > 0) {\n queryParams.append('sort', params.sort.join(','))\n }\n if (params?.language) {\n queryParams.append('language', params.language)\n }\n\n const queryString = queryParams.toString()\n const url = `${authStore.baseUrl}/api/v3.0/alerts${queryString ? `?${queryString}` : ''}`\n debug('Fetching alerts:', url)\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n 'Accept': 'application/json',\n 'Authorization': `Bearer ${authStore.token}`\n }\n })\n\n if (!response.ok) {\n return handleErrorResponse(response)\n }\n\n const data = await response.json() as PaginatedResult<Alert>\n debug('Alerts fetched:', data.results?.length ?? 0, 'alerts')\n\n return success(data)\n } catch (err) {\n return failure('NETWORK_ERROR', `Failed to fetch alerts: ${String(err)}`)\n }\n}\n\n/**\n * Get a specific alert by ID.\n *\n * @remarks\n * Fetches a single alert from `/api/v3.0/alerts/{alertId}`. Use the `include`\n * parameter to request additional fields.\n *\n * For more details, see the\n * [EEN API Documentation](https://developer.eagleeyenetworks.com/reference/getalert).\n *\n * @param alertId - The unique identifier of the alert to fetch\n * @param params - Optional parameters (e.g., include additional fields)\n * @returns A Result containing the alert or an error\n *\n * @example\n * ```typescript\n * import { getAlert } from 'een-api-toolkit'\n *\n * const { data, error } = await getAlert('alert-123')\n *\n * if (error) {\n * if (error.code === 'NOT_FOUND') {\n * console.log('Alert not found')\n * }\n * return\n * }\n *\n * console.log(`Alert: ${data.alertType} at ${data.timestamp}`)\n *\n * // With additional fields\n * const { data: alertWithData } = await getAlert('alert-123', {\n * include: ['data', 'actions', 'description']\n * })\n * ```\n *\n * @category Alerts\n */\nexport async function getAlert(alertId: string, params?: GetAlertParams): Promise<Result<Alert>> {\n const authStore = useAuthStore()\n\n if (!authStore.isAuthenticated) {\n return failure('AUTH_REQUIRED', 'Authentication required')\n }\n\n if (!authStore.baseUrl) {\n return failure('AUTH_REQUIRED', 'Base URL not configured')\n }\n\n if (!alertId) {\n return failure('VALIDATION_ERROR', 'Alert ID is required')\n }\n\n const queryParams = new URLSearchParams()\n\n if (params?.include && params.include.length > 0) {\n queryParams.append('include', params.include.join(','))\n }\n\n const queryString = queryParams.toString()\n const url = `${authStore.baseUrl}/api/v3.0/alerts/${encodeURIComponent(alertId)}${queryString ? `?${queryString}` : ''}`\n debug('Fetching alert:', url)\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n 'Accept': 'application/json',\n 'Authorization': `Bearer ${authStore.token}`\n }\n })\n\n if (!response.ok) {\n return handleErrorResponse(response)\n }\n\n const data = await response.json() as Alert\n debug('Alert fetched:', data.id)\n\n return success(data)\n } catch (err) {\n return failure('NETWORK_ERROR', `Failed to fetch alert: ${String(err)}`)\n }\n}\n\n/**\n * List all available alert types.\n *\n * @remarks\n * Fetches a paginated list of alert types from `/api/v3.0/alertTypes`. Alert types\n * describe the different kinds of alerts that can be generated in the system.\n *\n * For more details, see the\n * [EEN API Documentation](https://developer.eagleeyenetworks.com/reference/listalerttypes).\n *\n * @param params - Optional pagination parameters\n * @returns A Result containing a paginated list of alert types or an error\n *\n * @example\n * ```typescript\n * import { listAlertTypes } from 'een-api-toolkit'\n *\n * const { data, error } = await listAlertTypes()\n * if (data) {\n * data.results.forEach(alertType => {\n * console.log(`${alertType.type}: ${alertType.description}`)\n * })\n * }\n *\n * // With pagination\n * const { data: pagedTypes } = await listAlertTypes({ pageSize: 20 })\n * ```\n *\n * @category Alerts\n */\nexport async function listAlertTypes(params?: ListAlertTypesParams): Promise<Result<PaginatedResult<AlertType>>> {\n const authStore = useAuthStore()\n\n if (!authStore.isAuthenticated) {\n return failure('AUTH_REQUIRED', 'Authentication required')\n }\n\n if (!authStore.baseUrl) {\n return failure('AUTH_REQUIRED', 'Base URL not configured')\n }\n\n const queryParams = new URLSearchParams()\n\n // Pagination\n if (params?.pageSize) {\n queryParams.append('pageSize', String(params.pageSize))\n }\n if (params?.pageToken) {\n queryParams.append('pageToken', params.pageToken)\n }\n\n const queryString = queryParams.toString()\n const url = `${authStore.baseUrl}/api/v3.0/alertTypes${queryString ? `?${queryString}` : ''}`\n debug('Fetching alert types:', url)\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n 'Accept': 'application/json',\n 'Authorization': `Bearer ${authStore.token}`\n }\n })\n\n if (!response.ok) {\n return handleErrorResponse(response)\n }\n\n const data = await response.json() as PaginatedResult<AlertType>\n debug('Alert types fetched:', data.results?.length ?? 0, 'types')\n\n return success(data)\n } catch (err) {\n return failure('NETWORK_ERROR', `Failed to fetch alert types: ${String(err)}`)\n }\n}\n\n/**\n * Handle error responses from the API.\n * @internal\n */\nasync function handleErrorResponse<T>(response: Response): Promise<Result<T>> {\n const status = response.status\n\n let message: string\n try {\n const errorData = await response.json()\n message = errorData.message ?? errorData.error ?? response.statusText\n } catch (parseError) {\n debug('Failed to parse error response JSON:', parseError)\n message = response.statusText || 'Unknown error'\n }\n\n switch (status) {\n case 401:\n return failure('AUTH_REQUIRED', `Authentication failed: ${message}`, status)\n case 403:\n return failure('FORBIDDEN', `Access denied: ${message}`, status)\n case 404:\n return failure('NOT_FOUND', `Not found: ${message}`, status)\n case 429:\n return failure('RATE_LIMITED', `Rate limited: ${message}`, status)\n default:\n return failure('API_ERROR', `API error: ${message}`, status)\n }\n}\n","import { useAuthStore } from '../auth/store'\nimport { success, failure } from '../types'\nimport type {\n Result,\n PaginatedResult,\n Notification,\n ListNotificationsParams\n} from '../types'\nimport { debug, formatTimestamp } from '../utils'\n\n/**\n * List notifications with optional filters and pagination.\n *\n * @remarks\n * Fetches a paginated list of notifications from `/api/v3.0/notifications`. Supports\n * various filters including time range, actor, alert type, category, and more.\n *\n * For more details, see the\n * [EEN API Documentation](https://developer.eagleeyenetworks.com/reference/listnotifications).\n *\n * @param params - Optional filtering and pagination parameters\n * @returns A Result containing a paginated list of notifications or an error\n *\n * @example\n * ```typescript\n * import { listNotifications } from 'een-api-toolkit'\n *\n * // Get recent notifications for a specific camera\n * const { data, error } = await listNotifications({\n * actorId: '100d4c41',\n * timestamp__gte: new Date(Date.now() - 3600000).toISOString(),\n * pageSize: 50\n * })\n *\n * if (data) {\n * console.log(`Found ${data.results.length} notifications`)\n * data.results.forEach(notification => {\n * console.log(`${notification.category}: ${notification.description}`)\n * })\n * }\n *\n * // Get unread notifications\n * const { data: unread } = await listNotifications({\n * read: false,\n * category: 'video'\n * })\n *\n * // Fetch all notifications with pagination\n * let allNotifications: Notification[] = []\n * let pageToken: string | undefined\n * do {\n * const { data, error } = await listNotifications({\n * timestamp__gte: new Date(Date.now() - 86400000).toISOString(),\n * pageSize: 100,\n * pageToken\n * })\n * if (error) break\n * allNotifications.push(...data.results)\n * pageToken = data.nextPageToken\n * } while (pageToken)\n * ```\n *\n * @category Notifications\n */\nexport async function listNotifications(params?: ListNotificationsParams): Promise<Result<PaginatedResult<Notification>>> {\n const authStore = useAuthStore()\n\n if (!authStore.isAuthenticated) {\n return failure('AUTH_REQUIRED', 'Authentication required')\n }\n\n if (!authStore.baseUrl) {\n return failure('AUTH_REQUIRED', 'Base URL not configured')\n }\n\n const queryParams = new URLSearchParams()\n\n // Pagination\n if (params?.pageSize) {\n queryParams.append('pageSize', String(params.pageSize))\n }\n if (params?.pageToken) {\n queryParams.append('pageToken', params.pageToken)\n }\n\n // Time filters\n if (params?.timestamp__lte) {\n queryParams.append('timestamp__lte', formatTimestamp(params.timestamp__lte))\n }\n if (params?.timestamp__gte) {\n queryParams.append('timestamp__gte', formatTimestamp(params.timestamp__gte))\n }\n\n // Entity filters\n if (params?.alertId) {\n queryParams.append('alertId', params.alertId)\n }\n if (params?.alertType) {\n queryParams.append('alertType', params.alertType)\n }\n if (params?.actorId) {\n queryParams.append('actorId', params.actorId)\n }\n if (params?.actorType) {\n queryParams.append('actorType', params.actorType)\n }\n if (params?.actorAccountId) {\n queryParams.append('actorAccountId', params.actorAccountId)\n }\n\n // Category and status filters\n if (params?.category) {\n queryParams.append('category', params.category)\n }\n if (params?.userId) {\n queryParams.append('userId', params.userId)\n }\n if (params?.read !== undefined) {\n queryParams.append('read', String(params.read))\n }\n if (params?.status) {\n queryParams.append('status', params.status)\n }\n\n // Other options\n if (params?.includeV1Notifications !== undefined) {\n queryParams.append('includeV1Notifications', String(params.includeV1Notifications))\n }\n\n // Response options\n if (params?.sort && params.sort.length > 0) {\n queryParams.append('sort', params.sort.join(','))\n }\n if (params?.language) {\n queryParams.append('language', params.language)\n }\n\n const queryString = queryParams.toString()\n const url = `${authStore.baseUrl}/api/v3.0/notifications${queryString ? `?${queryString}` : ''}`\n debug('Fetching notifications:', url)\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n 'Accept': 'application/json',\n 'Authorization': `Bearer ${authStore.token}`\n }\n })\n\n if (!response.ok) {\n return handleErrorResponse(response)\n }\n\n const data = await response.json() as PaginatedResult<Notification>\n debug('Notifications fetched:', data.results?.length ?? 0, 'notifications')\n\n return success(data)\n } catch (err) {\n return failure('NETWORK_ERROR', `Failed to fetch notifications: ${String(err)}`)\n }\n}\n\n/**\n * Get a specific notification by ID.\n *\n * @remarks\n * Fetches a single notification from `/api/v3.0/notifications/{notificationId}`.\n *\n * For more details, see the\n * [EEN API Documentation](https://developer.eagleeyenetworks.com/reference/getnotification).\n *\n * @param notificationId - The unique identifier of the notification to fetch\n * @returns A Result containing the notification or an error\n *\n * @example\n * ```typescript\n * import { getNotification } from 'een-api-toolkit'\n *\n * const { data, error } = await getNotification('notification-123')\n *\n * if (error) {\n * if (error.code === 'NOT_FOUND') {\n * console.log('Notification not found')\n * }\n * return\n * }\n *\n * console.log(`Notification: ${data.category} - ${data.description}`)\n * console.log(`Read: ${data.read}`)\n * ```\n *\n * @category Notifications\n */\nexport async function getNotification(notificationId: string): Promise<Result<Notification>> {\n const authStore = useAuthStore()\n\n if (!authStore.isAuthenticated) {\n return failure('AUTH_REQUIRED', 'Authentication required')\n }\n\n if (!authStore.baseUrl) {\n return failure('AUTH_REQUIRED', 'Base URL not configured')\n }\n\n if (!notificationId) {\n return failure('VALIDATION_ERROR', 'Notification ID is required')\n }\n\n const url = `${authStore.baseUrl}/api/v3.0/notifications/${encodeURIComponent(notificationId)}`\n debug('Fetching notification:', url)\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n 'Accept': 'application/json',\n 'Authorization': `Bearer ${authStore.token}`\n }\n })\n\n if (!response.ok) {\n return handleErrorResponse(response)\n }\n\n const data = await response.json() as Notification\n debug('Notification fetched:', data.id)\n\n return success(data)\n } catch (err) {\n return failure('NETWORK_ERROR', `Failed to fetch notification: ${String(err)}`)\n }\n}\n\n/**\n * Handle error responses from the API.\n * @internal\n */\nasync function handleErrorResponse<T>(response: Response): Promise<Result<T>> {\n const status = response.status\n\n let message: string\n try {\n const errorData = await response.json()\n message = errorData.message ?? errorData.error ?? response.statusText\n } catch (parseError) {\n debug('Failed to parse error response JSON:', parseError)\n message = response.statusText || 'Unknown error'\n }\n\n switch (status) {\n case 401:\n return failure('AUTH_REQUIRED', `Authentication failed: ${message}`, status)\n case 403:\n return failure('FORBIDDEN', `Access denied: ${message}`, status)\n case 404:\n return failure('NOT_FOUND', `Not found: ${message}`, status)\n case 429:\n return failure('RATE_LIMITED', `Rate limited: ${message}`, status)\n default:\n return failure('API_ERROR', `API error: ${message}`, status)\n }\n}\n","import { useAuthStore } from '../auth/store'\nimport { success, failure } from '../types'\nimport type {\n Result,\n PaginatedResult,\n EventSubscription,\n CreateEventSubscriptionParams,\n ListEventSubscriptionsParams,\n SSEConnection,\n SSEConnectionOptions,\n SSEConnectionStatus,\n SSEEvent\n} from '../types'\nimport { debug } from '../utils'\n\n/**\n * List all event subscriptions for the current account.\n *\n * @remarks\n * Fetches a paginated list of event subscriptions from `/api/v3.0/eventSubscriptions`.\n *\n * For more details, see the\n * [EEN API Documentation](https://developer.eagleeyenetworks.com/reference/listeventsubscriptions).\n *\n * @param params - Optional pagination parameters\n * @returns A Result containing a paginated list of event subscriptions or an error\n *\n * @example\n * ```typescript\n * import { listEventSubscriptions } from 'een-api-toolkit'\n *\n * const { data, error } = await listEventSubscriptions()\n * if (data) {\n * console.log(`Found ${data.results.length} subscriptions`)\n * data.results.forEach(sub => {\n * console.log(`${sub.id}: ${sub.deliveryConfig.type}`)\n * })\n * }\n * ```\n *\n * @category EventSubscriptions\n */\nexport async function listEventSubscriptions(\n params?: ListEventSubscriptionsParams\n): Promise<Result<PaginatedResult<EventSubscription>>> {\n const authStore = useAuthStore()\n\n if (!authStore.isAuthenticated) {\n return failure('AUTH_REQUIRED', 'Authentication required')\n }\n\n if (!authStore.baseUrl) {\n return failure('AUTH_REQUIRED', 'Base URL not configured')\n }\n\n const queryParams = new URLSearchParams()\n\n if (params?.pageSize) {\n queryParams.append('pageSize', String(params.pageSize))\n }\n if (params?.pageToken) {\n queryParams.append('pageToken', params.pageToken)\n }\n\n const queryString = queryParams.toString()\n const url = `${authStore.baseUrl}/api/v3.0/eventSubscriptions${queryString ? `?${queryString}` : ''}`\n debug('Fetching event subscriptions:', url)\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n 'Accept': 'application/json',\n 'Authorization': `Bearer ${authStore.token}`\n }\n })\n\n if (!response.ok) {\n return handleErrorResponse(response)\n }\n\n const data = await response.json() as PaginatedResult<EventSubscription>\n debug('Event subscriptions fetched:', data.results?.length ?? 0, 'subscriptions')\n\n return success(data)\n } catch (err) {\n return failure('NETWORK_ERROR', `Failed to fetch event subscriptions: ${String(err)}`)\n }\n}\n\n/**\n * Get a specific event subscription by ID.\n *\n * @remarks\n * Fetches a single event subscription from `/api/v3.0/eventSubscriptions/{id}`.\n *\n * For more details, see the\n * [EEN API Documentation](https://developer.eagleeyenetworks.com/reference/geteventsubscription).\n *\n * @param subscriptionId - The unique identifier of the subscription to fetch\n * @returns A Result containing the event subscription or an error\n *\n * @example\n * ```typescript\n * import { getEventSubscription } from 'een-api-toolkit'\n *\n * const { data, error } = await getEventSubscription('f3d6f55d5ba546168758a309508f4419')\n * if (data) {\n * console.log(`Subscription: ${data.id}`)\n * if (data.deliveryConfig.type === 'serverSentEvents.v1') {\n * console.log(`SSE URL: ${data.deliveryConfig.sseUrl}`)\n * }\n * }\n * ```\n *\n * @category EventSubscriptions\n */\nexport async function getEventSubscription(\n subscriptionId: string\n): Promise<Result<EventSubscription>> {\n const authStore = useAuthStore()\n\n if (!authStore.isAuthenticated) {\n return failure('AUTH_REQUIRED', 'Authentication required')\n }\n\n if (!authStore.baseUrl) {\n return failure('AUTH_REQUIRED', 'Base URL not configured')\n }\n\n if (!subscriptionId) {\n return failure('VALIDATION_ERROR', 'Subscription ID is required')\n }\n\n const url = `${authStore.baseUrl}/api/v3.0/eventSubscriptions/${encodeURIComponent(subscriptionId)}`\n debug('Fetching event subscription:', url)\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n 'Accept': 'application/json',\n 'Authorization': `Bearer ${authStore.token}`\n }\n })\n\n if (!response.ok) {\n return handleErrorResponse(response)\n }\n\n const data = await response.json() as EventSubscription\n debug('Event subscription fetched:', data.id)\n\n return success(data)\n } catch (err) {\n return failure('NETWORK_ERROR', `Failed to fetch event subscription: ${String(err)}`)\n }\n}\n\n/**\n * Create a new event subscription.\n *\n * @remarks\n * Creates a new event subscription at `/api/v3.0/eventSubscriptions`.\n * For SSE subscriptions, use `connectToEventSubscription()` with the returned\n * `sseUrl` to start receiving events.\n *\n * For more details, see the\n * [EEN API Documentation](https://developer.eagleeyenetworks.com/reference/createeventsubscription).\n *\n * @param params - Parameters for creating the subscription\n * @returns A Result containing the created event subscription or an error\n *\n * @example\n * ```typescript\n * import { createEventSubscription, connectToEventSubscription } from 'een-api-toolkit'\n *\n * // Create an SSE subscription for motion events\n * const { data, error } = await createEventSubscription({\n * deliveryConfig: { type: 'serverSentEvents.v1' },\n * filters: [{\n * actors: ['camera:100d4c41'],\n * types: [{ id: 'een.motionDetectionEvent.v1' }]\n * }]\n * })\n *\n * if (data && data.deliveryConfig.type === 'serverSentEvents.v1') {\n * // Connect to the SSE stream\n * const { data: connection } = connectToEventSubscription(\n * data.deliveryConfig.sseUrl!,\n * { onEvent: (event) => console.log('Event:', event) }\n * )\n * }\n * ```\n *\n * @category EventSubscriptions\n */\nexport async function createEventSubscription(\n params: CreateEventSubscriptionParams\n): Promise<Result<EventSubscription>> {\n const authStore = useAuthStore()\n\n if (!authStore.isAuthenticated) {\n return failure('AUTH_REQUIRED', 'Authentication required')\n }\n\n if (!authStore.baseUrl) {\n return failure('AUTH_REQUIRED', 'Base URL not configured')\n }\n\n if (!params.deliveryConfig) {\n return failure('VALIDATION_ERROR', 'deliveryConfig is required')\n }\n\n if (!params.filters || params.filters.length === 0) {\n return failure('VALIDATION_ERROR', 'At least one filter is required')\n }\n\n // Validate each filter\n for (const filter of params.filters) {\n if (!filter.actors || filter.actors.length === 0) {\n return failure('VALIDATION_ERROR', 'Each filter must have at least one actor')\n }\n if (!filter.types || filter.types.length === 0) {\n return failure('VALIDATION_ERROR', 'Each filter must have at least one event type')\n }\n }\n\n const url = `${authStore.baseUrl}/api/v3.0/eventSubscriptions`\n debug('Creating event subscription:', url)\n\n try {\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Accept': 'application/json',\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${authStore.token}`\n },\n body: JSON.stringify(params)\n })\n\n if (!response.ok) {\n return handleErrorResponse(response)\n }\n\n const data = await response.json() as EventSubscription\n debug('Event subscription created:', data.id)\n\n return success(data)\n } catch (err) {\n return failure('NETWORK_ERROR', `Failed to create event subscription: ${String(err)}`)\n }\n}\n\n/**\n * Delete an event subscription.\n *\n * @remarks\n * Deletes an event subscription at `/api/v3.0/eventSubscriptions/{id}`.\n * Any active SSE connections to this subscription will be closed.\n *\n * For more details, see the\n * [EEN API Documentation](https://developer.eagleeyenetworks.com/reference/deleteeventsubscription).\n *\n * @param subscriptionId - The unique identifier of the subscription to delete\n * @returns A Result with void data on success or an error\n *\n * @example\n * ```typescript\n * import { deleteEventSubscription } from 'een-api-toolkit'\n *\n * const { error } = await deleteEventSubscription('f3d6f55d5ba546168758a309508f4419')\n * if (error) {\n * console.error('Failed to delete:', error.message)\n * } else {\n * console.log('Subscription deleted successfully')\n * }\n * ```\n *\n * @category EventSubscriptions\n */\nexport async function deleteEventSubscription(\n subscriptionId: string\n): Promise<Result<void>> {\n const authStore = useAuthStore()\n\n if (!authStore.isAuthenticated) {\n return failure('AUTH_REQUIRED', 'Authentication required')\n }\n\n if (!authStore.baseUrl) {\n return failure('AUTH_REQUIRED', 'Base URL not configured')\n }\n\n if (!subscriptionId) {\n return failure('VALIDATION_ERROR', 'Subscription ID is required')\n }\n\n const url = `${authStore.baseUrl}/api/v3.0/eventSubscriptions/${encodeURIComponent(subscriptionId)}`\n debug('Deleting event subscription:', url)\n\n try {\n const response = await fetch(url, {\n method: 'DELETE',\n headers: {\n 'Accept': 'application/json',\n 'Authorization': `Bearer ${authStore.token}`\n }\n })\n\n if (!response.ok) {\n return handleErrorResponse(response)\n }\n\n debug('Event subscription deleted:', subscriptionId)\n return success(undefined)\n } catch (err) {\n return failure('NETWORK_ERROR', `Failed to delete event subscription: ${String(err)}`)\n }\n}\n\n/**\n * Connect to an SSE event subscription to receive real-time events.\n *\n * @remarks\n * Opens an SSE connection to the provided URL and calls the `onEvent` callback\n * for each event received. The connection automatically handles reconnection\n * on errors.\n *\n * Note: SSE connections require authentication. The token is passed via the\n * `Authorization` header. Since EventSource doesn't support custom headers,\n * we use fetch with ReadableStream to implement SSE.\n *\n * @param sseUrl - The SSE URL from the event subscription's deliveryConfig\n * @param options - Connection options including event and error callbacks\n * @returns A Result containing the SSE connection handle or an error\n *\n * @example\n * ```typescript\n * import { createEventSubscription, connectToEventSubscription } from 'een-api-toolkit'\n *\n * // First create a subscription\n * const { data: subscription } = await createEventSubscription({\n * deliveryConfig: { type: 'serverSentEvents.v1' },\n * filters: [{\n * actors: ['camera:100d4c41'],\n * types: [{ id: 'een.motionDetectionEvent.v1' }]\n * }]\n * })\n *\n * if (subscription?.deliveryConfig.type === 'serverSentEvents.v1') {\n * // Connect to SSE stream\n * const { data: connection, error } = connectToEventSubscription(\n * subscription.deliveryConfig.sseUrl!,\n * {\n * onEvent: (event) => {\n * console.log(`Event: ${event.type} from ${event.actorId}`)\n * },\n * onError: (err) => {\n * console.error('SSE error:', err.message)\n * },\n * onStatusChange: (status) => {\n * console.log('Connection status:', status)\n * }\n * }\n * )\n *\n * // Later, disconnect\n * if (connection) {\n * connection.close()\n * }\n * }\n * ```\n *\n * @category EventSubscriptions\n */\nexport function connectToEventSubscription(\n sseUrl: string,\n options: SSEConnectionOptions\n): Result<SSEConnection> {\n const authStore = useAuthStore()\n\n if (!authStore.isAuthenticated) {\n return failure('AUTH_REQUIRED', 'Authentication required')\n }\n\n if (!authStore.token) {\n return failure('AUTH_REQUIRED', 'Access token not available')\n }\n\n if (!sseUrl) {\n return failure('VALIDATION_ERROR', 'SSE URL is required')\n }\n\n // Validate SSE URL domain to prevent SSRF attacks\n // SSE URLs should only come from trusted EEN domains\n try {\n const sseUrlObj = new URL(sseUrl)\n const allowedDomains = ['.eagleeyenetworks.com', '.een.cloud']\n // Allow both exact domain match (e.g., eagleeyenetworks.com) and subdomain match (e.g., api.eagleeyenetworks.com)\n const isAllowedDomain = allowedDomains.some(domain =>\n sseUrlObj.hostname === domain.substring(1) || sseUrlObj.hostname.endsWith(domain)\n )\n if (!isAllowedDomain) {\n return failure('VALIDATION_ERROR', `SSE URL domain not allowed: ${sseUrlObj.hostname}`)\n }\n } catch {\n return failure('VALIDATION_ERROR', 'Invalid SSE URL format')\n }\n\n // Maximum buffer size to prevent memory exhaustion (1MB)\n const MAX_BUFFER_SIZE = 1024 * 1024\n\n let status: SSEConnectionStatus = 'connecting'\n let abortController: AbortController | null = new AbortController()\n let isClosing = false\n\n const setStatus = (newStatus: SSEConnectionStatus) => {\n status = newStatus\n options.onStatusChange?.(status)\n }\n\n const close = () => {\n if (isClosing) return\n isClosing = true\n debug('Closing SSE connection')\n abortController?.abort()\n abortController = null\n setStatus('disconnected')\n }\n\n const connect = async () => {\n if (isClosing || !abortController) return\n\n setStatus('connecting')\n debug('Connecting to SSE:', sseUrl)\n\n try {\n // Note: We intentionally omit Cache-Control header here.\n // While 'Cache-Control: no-cache' is common for SSE, it triggers CORS preflight\n // requests that fail because the EEN API doesn't include it in Access-Control-Allow-Headers.\n // The SSE endpoint handles caching appropriately server-side.\n const response = await fetch(sseUrl, {\n method: 'GET',\n headers: {\n 'Accept': 'text/event-stream',\n 'Authorization': `Bearer ${authStore.token}`\n },\n signal: abortController.signal\n })\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`)\n }\n\n if (!response.body) {\n throw new Error('Response body is not available')\n }\n\n setStatus('connected')\n debug('SSE connected')\n\n const reader = response.body.getReader()\n const decoder = new TextDecoder()\n let buffer = ''\n\n while (!isClosing) {\n const { done, value } = await reader.read()\n\n if (done) {\n debug('SSE stream ended')\n break\n }\n\n buffer += decoder.decode(value, { stream: true })\n\n // Prevent buffer from growing unbounded (protects against memory exhaustion)\n if (buffer.length > MAX_BUFFER_SIZE) {\n debug('SSE buffer exceeded maximum size, resetting')\n buffer = ''\n continue\n }\n\n const lines = buffer.split('\\n')\n buffer = lines.pop() || ''\n\n let eventData = ''\n for (const line of lines) {\n if (line.startsWith('data:')) {\n // Per SSE spec, multi-line data fields are concatenated with newlines\n const dataValue = line.substring(5).trimStart()\n eventData = eventData ? `${eventData}\\n${dataValue}` : dataValue\n } else if (line === '' && eventData) {\n // End of event\n try {\n const event = JSON.parse(eventData) as SSEEvent\n debug('SSE event received:', event.type, event.actorId)\n options.onEvent(event)\n } catch (parseError) {\n debug('Failed to parse SSE event:', parseError)\n }\n eventData = ''\n }\n }\n }\n } catch (err) {\n if (isClosing || (err instanceof Error && err.name === 'AbortError')) {\n // Expected when closing\n return\n }\n\n debug('SSE error:', err)\n setStatus('error')\n options.onError?.(err instanceof Error ? err : new Error(String(err)))\n }\n }\n\n // Start connection\n connect()\n\n const connection: SSEConnection = {\n close,\n get status() {\n return status\n }\n }\n\n return success(connection)\n}\n\n/**\n * Handle error responses from the API.\n * @internal\n */\nasync function handleErrorResponse<T>(response: Response): Promise<Result<T>> {\n const status = response.status\n\n let message: string\n try {\n const errorData = await response.json()\n message = errorData.message ?? errorData.error ?? response.statusText\n } catch (parseError) {\n debug('Failed to parse error response JSON:', parseError)\n message = response.statusText || 'Unknown error'\n }\n\n switch (status) {\n case 401:\n return failure('AUTH_REQUIRED', message, status)\n case 403:\n return failure('FORBIDDEN', message, status)\n case 404:\n return failure('NOT_FOUND', message, status)\n case 429:\n return failure('RATE_LIMITED', message, status)\n default:\n return failure('API_ERROR', message, status)\n }\n}\n"],"names":["isDebugEnabled","__vite_import_meta_env__","debug","args","STORAGE_STRATEGY_DESCRIPTIONS","MemoryStorage","key","value","BrowserStorageAdapter","storage","currentStrategy","memoryStorageInstance","getMemoryStorage","setStorageStrategy","strategy","getStorageStrategy","getStorageAdapter","config","initEenToolkit","options","storageStrategy","getConfig","getProxyUrl","getClientId","getRedirectUri","success","data","failure","code","message","status","details","formatTimestamp","timestamp","refreshTokenFnPromise","getRefreshTokenFn","service","useAuthStore","defineStore","token","ref","tokenExpiration","refreshTokenMarker","sessionId","hostname","port","userProfile","refreshTimerId","isRefreshing","refreshPromise","refreshFailed","refreshFailedMessage","isAuthenticated","computed","baseUrl","isTokenExpired","tokenExpiresIn","setToken","newToken","expiresIn","saveToStorage","setupAutoRefresh","setRefreshTokenMarker","marker","setSessionId","newSessionId","setBaseUrl","url","err","setUserProfile","profile","now","timeUntilExpiry","fiveMinutes","halfTtl","refreshBuffer","refreshTime","timeout","performAutoRefresh","result","clearRefreshFailed","logout","clearStorage","initialize","loadFromStorage","expStr","portStr","profileStr","EEN_AUTH_URL","getAuthUrl","clientId","state","params","getAccessToken","proxyUrl","response","errorText","refreshToken","authStore","headers","revokeToken","handleAuthCallback","storedState","constantTimeEquals","a","b","getCurrentUser","handleErrorResponse","getUsers","queryParams","queryString","getUser","userId","errorData","getCameras","getCamera","cameraId","parseError","getBridges","getBridge","bridgeId","DEFAULT_TIMEOUT_MS","createTimeoutController","timeoutMs","controller","timeoutId","arrayBufferToBase64","buffer","bytes","chunkSize","chunks","i","chunk","str","j","binary","listMedia","getLiveImage","type","prevToken","arrayBuffer","imageData","getRecordedImage","nextToken","overlaySvg","getMediaSession","initMediaSession","sessionResult","sessionUrl","listFeeds","apiMessage","listEvents","getEvent","eventId","listEventTypes","listEventFieldValues","getEventMetrics","listAlerts","getAlert","alertId","listAlertTypes","listNotifications","getNotification","notificationId","listEventSubscriptions","getEventSubscription","subscriptionId","createEventSubscription","filter","deleteEventSubscription","connectToEventSubscription","sseUrl","sseUrlObj","domain","MAX_BUFFER_SIZE","abortController","isClosing","setStatus","newStatus","close","reader","decoder","done","lines","eventData","line","dataValue","event"],"mappings":"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"}