een-api-toolkit 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,67 +2,23 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
- ## [0.1.2] - 2025-12-30
5
+ ## [0.1.4] - 2025-12-31
6
6
 
7
7
  ### Release Summary
8
8
 
9
- #### PR #31: Release v0.0.18: Documentation improvements and PR validation
10
- ## Summary
11
-
12
- This release includes documentation improvements based on user feedback and a new CI workflow to validate PRs before merge.
13
-
14
- ### Changes
15
-
16
- **docs: Improve AI-CONTEXT.md with critical setup info at top**
17
- - Added "Prerequisites & Installation (READ FIRST)" section
18
- - Installation command now includes pinia: `npm install een-api-toolkit pinia`
19
- - Complete main.ts example with numbered steps
20
- - Common Errors section for Pinia and OAuth issues
21
-
22
- **docs: Address Gemini review feedback**
23
- - OAuth Callback Route: Added sentence linking to beforeEnter guard
24
- - Logout: Changed to full Vue component example with useRouter
25
-
26
- **ci: Add PR validation workflow**
27
- - New `validate-pr.yml` workflow runs on PRs to production
28
- - Validates version consistency across package.json, AI-CONTEXT.md, and docs/api
29
- - Checks if version is already published to npm
30
- - Runs quick validation tests (lint, typecheck, unit tests, build, docs)
31
-
32
- ### New Commits (since last merge)
33
-
34
- - `d62fadc` ci: Add PR validation workflow for version consistency
35
- - `29ad8f6` docs: Address Gemini review feedback
36
-
37
- ### Test Results
38
-
39
- - ✅ Lint: Passed (1 warning - expected)
40
- - ✅ Unit tests: 33 passed
41
- - ✅ Build: Success
42
-
43
- ### Version
44
-
45
- `0.0.18`
46
-
47
- ---
48
-
49
- 🤖 Generated with [Claude Code](https://claude.com/claude-code)
50
-
9
+ No PR descriptions available for this release.
51
10
 
52
11
  ### Detailed Changes
53
12
 
54
- #### Other Changes
55
- - refactor: Rename vue-basic example to vue-users
56
- - docs: Add v-else fallback to Vue template example
57
- - test: Add service function unit tests, fix pagination, bump to 0.1.0
58
- - refactor: Remove Vue 3 Composables, keep plain async functions only
59
- - docs: Address code review feedback
60
- - ci: Add PR validation workflow for version consistency
61
- - docs: Address Gemini review feedback
13
+ #### Features
14
+ - feat: Add bridges API with getBridges and getBridge functions
15
+
16
+ #### Bug Fixes
17
+ - fix: Address code review feedback for bridges API
62
18
 
63
19
  ### Links
64
20
  - [npm package](https://www.npmjs.com/package/een-api-toolkit)
65
- - [Full Changelog](https://github.com/klaushofrichter/een-api-toolkit/compare/v0.0.18...v0.1.2)
21
+ - [Full Changelog](https://github.com/klaushofrichter/een-api-toolkit/compare/v0.1.2...v0.1.4)
66
22
 
67
23
  ---
68
- *Released: 2025-12-30 19:11:38 CST*
24
+ *Released: 2025-12-31 11:11:58 CST*
package/dist/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const te=require("pinia"),d=require("vue"),g={};let E={};function ne(e={}){E={proxyUrl:e.proxyUrl??g?.VITE_PROXY_URL,clientId:e.clientId??g?.VITE_EEN_CLIENT_ID,redirectUri:e.redirectUri??g?.VITE_REDIRECT_URI,debug:e.debug??g?.VITE_DEBUG==="true"}}function re(){return E}function U(){return E.proxyUrl??g?.VITE_PROXY_URL}function O(){return E.clientId??g?.VITE_EEN_CLIENT_ID}function m(){return E.redirectUri??g?.VITE_REDIRECT_URI??"http://127.0.0.1:3333"}function _(e){return{data:e,error:null}}function i(e,n,t,r){return{data:null,error:{code:e,message:n,status:t,details:r}}}const oe={BASE_URL:"/",DEV:!1,MODE:"production",PROD:!0,SSR:!1},ie=()=>{try{return oe?.VITE_DEBUG==="true"}catch{return!1}};function c(...e){ie()&&console.log("[een-api-toolkit]",...e)}let y=null;function ae(){return y||(y=Promise.resolve().then(()=>le).then(e=>e.refreshToken)),y}const h=te.defineStore("een-auth",()=>{const e=d.ref(null),n=d.ref(null),t=d.ref(null),r=d.ref(null),a=d.ref(null),o=d.ref(443),l=d.ref(null),f=d.ref(null),S=d.ref(!1);let T=null;const I=d.ref(!1),R=d.ref(null),N=d.computed(()=>!!e.value),w=d.computed(()=>a.value?o.value===443?`https://${a.value}`:`https://${a.value}:${o.value}`:null),A=d.computed(()=>n.value?Date.now()>=n.value:!0),q=d.computed(()=>n.value?Math.max(0,n.value-Date.now()):0);function B(s,u){e.value=s,n.value=Date.now()+u*1e3,p(),k(),c("Token set, expires in",u,"seconds")}function H(s){t.value=s,p()}function M(s){r.value=s,p()}function z(s){if(typeof s=="string")try{const u=new URL(s.startsWith("http")?s:`https://${s}`);a.value=u.hostname,o.value=u.port?parseInt(u.port,10):443}catch(u){c("Failed to parse URL, using as hostname:",u instanceof Error?u.message:String(u)),a.value=s,o.value=443}else a.value=s.hostname,o.value=s.port??443;p(),c("Base URL set:",w.value)}function V(s){l.value=s,p()}function k(){if(f.value&&(clearTimeout(f.value),f.value=null),!n.value||!e.value)return;const s=Date.now(),v=n.value-s,X=300*1e3,Y=v/2,Z=Math.min(X,Y),ee=Math.max(v-Z,60*1e3),C=Math.max(ee,5e3);c("Auto-refresh scheduled in",Math.round(C/1e3),"seconds"),f.value=setTimeout(async()=>{await Q()},C)}async function Q(){return T?(c("Refresh already in progress, waiting for existing refresh"),T):(S.value=!0,c("Performing auto-refresh"),T=(async()=>{try{const u=await(await ae())();u.error?(I.value=!0,R.value=u.error.message,c("Auto-refresh failed:",u.error.message)):(I.value=!1,R.value=null,c("Auto-refresh successful"))}catch(s){I.value=!0,R.value=s instanceof Error?s.message:String(s),c("Auto-refresh error:",s)}finally{S.value=!1,T=null}})(),T)}function W(){I.value=!1,R.value=null}function x(){f.value&&(clearTimeout(f.value),f.value=null),e.value=null,n.value=null,t.value=null,r.value=null,a.value=null,o.value=443,l.value=null,I.value=!1,R.value=null,J(),c("Logged out")}function G(){K(),e.value&&!A.value?(k(),c("Initialized from storage")):e.value&&A.value&&(c("Stored token expired, clearing"),x())}function p(){try{e.value&&localStorage.setItem("een_token",e.value),n.value&&localStorage.setItem("een_tokenExpiration",String(n.value)),t.value&&localStorage.setItem("een_refreshTokenMarker",t.value),r.value&&localStorage.setItem("een_sessionId",r.value),a.value&&localStorage.setItem("een_hostname",a.value),o.value!==443&&localStorage.setItem("een_port",String(o.value)),l.value&&localStorage.setItem("een_userProfile",JSON.stringify(l.value))}catch(s){c("Failed to save to localStorage:",s instanceof Error?s.message:String(s))}}function K(){try{e.value=localStorage.getItem("een_token");const s=localStorage.getItem("een_tokenExpiration");n.value=s?parseInt(s,10):null,t.value=localStorage.getItem("een_refreshTokenMarker"),r.value=localStorage.getItem("een_sessionId"),a.value=localStorage.getItem("een_hostname");const u=localStorage.getItem("een_port");o.value=u?parseInt(u,10):443;const v=localStorage.getItem("een_userProfile");l.value=v?JSON.parse(v):null}catch(s){c("Failed to load from localStorage:",s instanceof Error?s.message:String(s))}}function J(){try{localStorage.removeItem("een_token"),localStorage.removeItem("een_tokenExpiration"),localStorage.removeItem("een_refreshTokenMarker"),localStorage.removeItem("een_sessionId"),localStorage.removeItem("een_hostname"),localStorage.removeItem("een_port"),localStorage.removeItem("een_userProfile")}catch(s){c("Failed to clear localStorage:",s instanceof Error?s.message:String(s))}}return{token:e,tokenExpiration:n,refreshTokenMarker:t,sessionId:r,hostname:a,port:o,userProfile:l,isRefreshing:S,refreshFailed:I,refreshFailedMessage:R,isAuthenticated:N,baseUrl:w,isTokenExpired:A,tokenExpiresIn:q,setToken:B,setRefreshTokenMarker:H,setSessionId:M,setBaseUrl:z,setUserProfile:V,setupAutoRefresh:k,clearRefreshFailed:W,logout:x,initialize:G}}),se="https://auth.eagleeyenetworks.com/oauth2/authorize";function P(){const e=O();if(!e)throw new Error("Client ID not configured. Call initEenToolkit() or set VITE_EEN_CLIENT_ID");const n=crypto.randomUUID();try{sessionStorage.setItem("een_oauth_state",n)}catch{}const t=new URLSearchParams({client_id:e,response_type:"code",scope:"vms.all",redirect_uri:m(),state:n});return c("Generated auth URL with state:",n),`${se}?${t.toString()}`}async function $(e){const n=U();if(!n)return i("AUTH_FAILED","Proxy URL not configured. Call initEenToolkit() or set VITE_PROXY_URL");const t=new URLSearchParams({code:e,redirect_uri:m()});try{const r=await fetch(`${n}/proxy/getAccessToken?${t.toString()}`,{method:"POST",credentials:"include",headers:{Accept:"application/json"}});if(!r.ok){const o=await r.text().catch(()=>"Unknown error");return i("AUTH_FAILED",`Token exchange failed: ${o}`,r.status)}const a=await r.json();return c("Token received, expires in:",a.expiresIn),_(a)}catch(r){return i("NETWORK_ERROR",`Failed to exchange code: ${String(r)}`)}}async function L(){const e=U();if(!e)return i("AUTH_FAILED","Proxy URL not configured");const n=h();try{const t={Accept:"application/json"};n.sessionId&&(t.Authorization=`Bearer ${n.sessionId}`);const r=await fetch(`${e}/proxy/refreshAccessToken`,{method:"POST",credentials:"include",headers:t});if(!r.ok){const o=await r.text().catch(()=>"Unknown error");return i("AUTH_FAILED",`Token refresh failed: ${o}`,r.status)}const a=await r.json();return n.setToken(a.accessToken,a.expiresIn),c("Token refreshed, expires in:",a.expiresIn),_(a)}catch(t){return i("NETWORK_ERROR",`Failed to refresh token: ${String(t)}`)}}async function j(){const e=U();if(!e)return i("AUTH_FAILED","Proxy URL not configured");const n=h();try{const t={Accept:"application/json"};n.sessionId&&(t.Authorization=`Bearer ${n.sessionId}`);const r=await fetch(`${e}/proxy/revoke`,{method:"POST",credentials:"include",headers:t});if(n.logout(),!r.ok){const a=await r.text().catch(()=>"Unknown error");return i("AUTH_FAILED",`Token revocation failed: ${a}`,r.status)}return c("Token revoked"),_(void 0)}catch(t){return n.logout(),i("NETWORK_ERROR",`Failed to revoke token: ${String(t)}`)}}async function F(e,n){let t=null;try{t=sessionStorage.getItem("een_oauth_state"),sessionStorage.removeItem("een_oauth_state")}catch{}if(!t)return i("AUTH_FAILED","No OAuth state found. Please restart the login process.");if(!ce(n,t))return i("AUTH_FAILED","Invalid OAuth state. Possible CSRF attack.");c("State validated, exchanging code for token");const r=await $(e);if(r.error)return r;const a=h(),o=r.data;return a.setToken(o.accessToken,o.expiresIn),a.setRefreshTokenMarker("present"),a.setSessionId(o.sessionId),a.setBaseUrl(o.httpsBaseUrl),c("Auth callback complete, user:",o.userEmail),_(o)}function ce(e,n){if(e.length!==n.length)return!1;let t=0;for(let r=0;r<e.length;r++)t|=e.charCodeAt(r)^n.charCodeAt(r);return t===0}const le=Object.freeze(Object.defineProperty({__proto__:null,getAccessToken:$,getAuthUrl:P,handleAuthCallback:F,refreshToken:L,revokeToken:j},Symbol.toStringTag,{value:"Module"}));async function ue(){const e=h();if(!e.isAuthenticated)return i("AUTH_REQUIRED","Authentication required");if(!e.baseUrl)return i("AUTH_REQUIRED","Base URL not configured");const n=`${e.baseUrl}/api/v3.0/users/self`;c("Fetching current user:",n);try{const t=await fetch(n,{method:"GET",headers:{Accept:"application/json",Authorization:`Bearer ${e.token}`}});if(!t.ok)return D(t);const r=await t.json();return c("Current user fetched:",r.email),e.setUserProfile(r),_(r)}catch(t){return i("NETWORK_ERROR",`Failed to fetch current user: ${String(t)}`)}}async function de(e){const n=h();if(!n.isAuthenticated)return i("AUTH_REQUIRED","Authentication required");if(!n.baseUrl)return i("AUTH_REQUIRED","Base URL not configured");const t=new URLSearchParams;e?.pageSize&&t.append("pageSize",String(e.pageSize)),e?.pageToken&&t.append("pageToken",e.pageToken),e?.include&&e.include.length>0&&t.append("include",e.include.join(","));const r=t.toString(),a=`${n.baseUrl}/api/v3.0/users${r?`?${r}`:""}`;c("Fetching users:",a);try{const o=await fetch(a,{method:"GET",headers:{Accept:"application/json",Authorization:`Bearer ${n.token}`}});if(!o.ok)return D(o);const l=await o.json();return c("Users fetched:",l.results?.length??0,"users"),_(l)}catch(o){return i("NETWORK_ERROR",`Failed to fetch users: ${String(o)}`)}}async function fe(e,n){const t=h();if(!t.isAuthenticated)return i("AUTH_REQUIRED","Authentication required");if(!t.baseUrl)return i("AUTH_REQUIRED","Base URL not configured");if(!e)return i("VALIDATION_ERROR","User ID is required");const r=new URLSearchParams;n?.include&&n.include.length>0&&r.append("include",n.include.join(","));const a=r.toString(),o=`${t.baseUrl}/api/v3.0/users/${encodeURIComponent(e)}${a?`?${a}`:""}`;c("Fetching user:",o);try{const l=await fetch(o,{method:"GET",headers:{Accept:"application/json",Authorization:`Bearer ${t.token}`}});if(!l.ok)return D(l);const f=await l.json();return c("User fetched:",f.email),_(f)}catch(l){return i("NETWORK_ERROR",`Failed to fetch user: ${String(l)}`)}}async function D(e){const n=e.status;let t;try{const r=await e.json();t=r.message??r.error??e.statusText}catch{t=e.statusText||"Unknown error"}switch(n){case 401:return i("AUTH_REQUIRED",`Authentication failed: ${t}`,n);case 403:return i("FORBIDDEN",`Access denied: ${t}`,n);case 404:return i("NOT_FOUND",`Not found: ${t}`,n);case 429:return i("RATE_LIMITED",`Rate limited: ${t}`,n);default:return i("API_ERROR",`API error: ${t}`,n)}}async function _e(e){const n=h();if(!n.isAuthenticated)return i("AUTH_REQUIRED","Authentication required");if(!n.baseUrl)return i("AUTH_REQUIRED","Base URL not configured");const t=new URLSearchParams;e?.pageSize&&t.append("pageSize",String(e.pageSize)),e?.pageToken&&t.append("pageToken",e.pageToken),e?.include&&e.include.length>0&&t.append("include",e.include.join(",")),e?.sort&&e.sort.length>0&&t.append("sort",e.sort.join(",")),e?.locationId__in&&e.locationId__in.length>0&&t.append("locationId__in",e.locationId__in.join(",")),e?.bridgeId__in&&e.bridgeId__in.length>0&&t.append("bridgeId__in",e.bridgeId__in.join(",")),e?.multiCameraId&&t.append("multiCameraId",e.multiCameraId),e?.multiCameraId__ne&&t.append("multiCameraId__ne",e.multiCameraId__ne),e?.multiCameraId__in&&e.multiCameraId__in.length>0&&t.append("multiCameraId__in",e.multiCameraId__in.join(",")),e?.tags__contains&&e.tags__contains.length>0&&t.append("tags__contains",e.tags__contains.join(",")),e?.tags__any&&e.tags__any.length>0&&t.append("tags__any",e.tags__any.join(",")),e?.packages__contains&&e.packages__contains.length>0&&t.append("packages__contains",e.packages__contains.join(",")),e?.name&&t.append("name",e.name),e?.name__contains&&t.append("name__contains",e.name__contains),e?.name__in&&e.name__in.length>0&&t.append("name__in",e.name__in.join(",")),e?.id__in&&e.id__in.length>0&&t.append("id__in",e.id__in.join(",")),e?.id__notIn&&e.id__notIn.length>0&&t.append("id__notIn",e.id__notIn.join(",")),e?.id__contains&&t.append("id__contains",e.id__contains),e?.layoutId&&t.append("layoutId",e.layoutId),typeof e?.shared=="boolean"&&t.append("shareDetails.shared",String(e.shared)),e?.sharedCameraAccount&&t.append("shareDetails.accountId",e.sharedCameraAccount),typeof e?.firstResponder=="boolean"&&t.append("shareDetails.firstResponder",String(e.firstResponder)),typeof e?.directToCloud=="boolean"&&t.append("deviceInfo.directToCloud",String(e.directToCloud)),e?.speakerId__in&&e.speakerId__in.length>0&&t.append("speakerId__in",e.speakerId__in.join(",")),e?.q&&t.append("q",e.q),typeof e?.qRelevance__gte=="number"&&t.append("qRelevance__gte",String(e.qRelevance__gte)),e?.enabledAnalytics__contains&&e.enabledAnalytics__contains.length>0&&t.append("enabledAnalytics__contains",e.enabledAnalytics__contains.join(",")),e?.status__in&&e.status__in.length>0&&t.append("status__in",e.status__in.join(",")),e?.status__ne&&t.append("status__ne",e.status__ne);const r=t.toString(),a=`${n.baseUrl}/api/v3.0/cameras${r?`?${r}`:""}`;c("Fetching cameras:",a);try{const o=await fetch(a,{method:"GET",headers:{Accept:"application/json",Authorization:`Bearer ${n.token}`}});if(!o.ok)return b(o);const l=await o.json();return c("Cameras fetched:",l.results?.length??0,"cameras"),_(l)}catch(o){return i("NETWORK_ERROR",`Failed to fetch cameras: ${String(o)}`)}}async function he(e,n){const t=h();if(!t.isAuthenticated)return i("AUTH_REQUIRED","Authentication required");if(!t.baseUrl)return i("AUTH_REQUIRED","Base URL not configured");if(!e)return i("VALIDATION_ERROR","Camera ID is required");const r=new URLSearchParams;n?.include&&n.include.length>0&&r.append("include",n.include.join(","));const a=r.toString(),o=`${t.baseUrl}/api/v3.0/cameras/${encodeURIComponent(e)}${a?`?${a}`:""}`;c("Fetching camera:",o);try{const l=await fetch(o,{method:"GET",headers:{Accept:"application/json",Authorization:`Bearer ${t.token}`}});if(!l.ok)return b(l);const f=await l.json();return c("Camera fetched:",f.name),_(f)}catch(l){return i("NETWORK_ERROR",`Failed to fetch camera: ${String(l)}`)}}async function b(e){const n=e.status;let t;try{const r=await e.json();t=r.message??r.error??e.statusText}catch(r){c("Failed to parse error response JSON:",r),t=e.statusText||"Unknown error"}switch(n){case 401:return i("AUTH_REQUIRED",`Authentication failed: ${t}`,n);case 403:return i("FORBIDDEN",`Access denied: ${t}`,n);case 404:return i("NOT_FOUND",`Not found: ${t}`,n);case 429:return i("RATE_LIMITED",`Rate limited: ${t}`,n);default:return i("API_ERROR",`API error: ${t}`,n)}}exports.failure=i;exports.getAccessToken=$;exports.getAuthUrl=P;exports.getCamera=he;exports.getCameras=_e;exports.getClientId=O;exports.getConfig=re;exports.getCurrentUser=ue;exports.getProxyUrl=U;exports.getRedirectUri=m;exports.getUser=fe;exports.getUsers=de;exports.handleAuthCallback=F;exports.initEenToolkit=ne;exports.refreshToken=L;exports.revokeToken=j;exports.success=_;exports.useAuthStore=h;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const ne=require("pinia"),_=require("vue"),h={};let p={};function re(e={}){p={proxyUrl:e.proxyUrl??h?.VITE_PROXY_URL,clientId:e.clientId??h?.VITE_EEN_CLIENT_ID,redirectUri:e.redirectUri??h?.VITE_REDIRECT_URI,debug:e.debug??h?.VITE_DEBUG==="true"}}function oe(){return p}function S(){return p.proxyUrl??h?.VITE_PROXY_URL}function x(){return p.clientId??h?.VITE_EEN_CLIENT_ID}function $(){return p.redirectUri??h?.VITE_REDIRECT_URI??"http://127.0.0.1:3333"}function f(e){return{data:e,error:null}}function o(e,n,t,r){return{data:null,error:{code:e,message:n,status:t,details:r}}}const ie={BASE_URL:"/",DEV:!1,MODE:"production",PROD:!0,SSR:!1},ae=()=>{try{return ie?.VITE_DEBUG==="true"}catch{return!1}};function c(...e){ae()&&console.log("[een-api-toolkit]",...e)}let y=null;function se(){return y||(y=Promise.resolve().then(()=>le).then(e=>e.refreshToken)),y}const g=ne.defineStore("een-auth",()=>{const e=_.ref(null),n=_.ref(null),t=_.ref(null),r=_.ref(null),a=_.ref(null),i=_.ref(443),u=_.ref(null),d=_.ref(null),v=_.ref(!1);let T=null;const R=_.ref(!1),I=_.ref(null),N=_.computed(()=>!!e.value),w=_.computed(()=>a.value?i.value===443?`https://${a.value}`:`https://${a.value}:${i.value}`:null),A=_.computed(()=>n.value?Date.now()>=n.value:!0),B=_.computed(()=>n.value?Math.max(0,n.value-Date.now()):0);function H(s,l){e.value=s,n.value=Date.now()+l*1e3,E(),k(),c("Token set, expires in",l,"seconds")}function z(s){t.value=s,E()}function M(s){r.value=s,E()}function Q(s){if(typeof s=="string")try{const l=new URL(s.startsWith("http")?s:`https://${s}`);a.value=l.hostname,i.value=l.port?parseInt(l.port,10):443}catch(l){c("Failed to parse URL, using as hostname:",l instanceof Error?l.message:String(l)),a.value=s,i.value=443}else a.value=s.hostname,i.value=s.port??443;E(),c("Base URL set:",w.value)}function V(s){u.value=s,E()}function k(){if(d.value&&(clearTimeout(d.value),d.value=null),!n.value||!e.value)return;const s=Date.now(),U=n.value-s,Y=300*1e3,Z=U/2,ee=Math.min(Y,Z),te=Math.max(U-ee,60*1e3),j=Math.max(te,5e3);c("Auto-refresh scheduled in",Math.round(j/1e3),"seconds"),d.value=setTimeout(async()=>{await W()},j)}async function W(){return T?(c("Refresh already in progress, waiting for existing refresh"),T):(v.value=!0,c("Performing auto-refresh"),T=(async()=>{try{const l=await(await se())();l.error?(R.value=!0,I.value=l.error.message,c("Auto-refresh failed:",l.error.message)):(R.value=!1,I.value=null,c("Auto-refresh successful"))}catch(s){R.value=!0,I.value=s instanceof Error?s.message:String(s),c("Auto-refresh error:",s)}finally{v.value=!1,T=null}})(),T)}function G(){R.value=!1,I.value=null}function O(){d.value&&(clearTimeout(d.value),d.value=null),e.value=null,n.value=null,t.value=null,r.value=null,a.value=null,i.value=443,u.value=null,R.value=!1,I.value=null,X(),c("Logged out")}function K(){J(),e.value&&!A.value?(k(),c("Initialized from storage")):e.value&&A.value&&(c("Stored token expired, clearing"),O())}function E(){try{e.value&&localStorage.setItem("een_token",e.value),n.value&&localStorage.setItem("een_tokenExpiration",String(n.value)),t.value&&localStorage.setItem("een_refreshTokenMarker",t.value),r.value&&localStorage.setItem("een_sessionId",r.value),a.value&&localStorage.setItem("een_hostname",a.value),i.value!==443&&localStorage.setItem("een_port",String(i.value)),u.value&&localStorage.setItem("een_userProfile",JSON.stringify(u.value))}catch(s){c("Failed to save to localStorage:",s instanceof Error?s.message:String(s))}}function J(){try{e.value=localStorage.getItem("een_token");const s=localStorage.getItem("een_tokenExpiration");n.value=s?parseInt(s,10):null,t.value=localStorage.getItem("een_refreshTokenMarker"),r.value=localStorage.getItem("een_sessionId"),a.value=localStorage.getItem("een_hostname");const l=localStorage.getItem("een_port");i.value=l?parseInt(l,10):443;const U=localStorage.getItem("een_userProfile");u.value=U?JSON.parse(U):null}catch(s){c("Failed to load from localStorage:",s instanceof Error?s.message:String(s))}}function X(){try{localStorage.removeItem("een_token"),localStorage.removeItem("een_tokenExpiration"),localStorage.removeItem("een_refreshTokenMarker"),localStorage.removeItem("een_sessionId"),localStorage.removeItem("een_hostname"),localStorage.removeItem("een_port"),localStorage.removeItem("een_userProfile")}catch(s){c("Failed to clear localStorage:",s instanceof Error?s.message:String(s))}}return{token:e,tokenExpiration:n,refreshTokenMarker:t,sessionId:r,hostname:a,port:i,userProfile:u,isRefreshing:v,refreshFailed:R,refreshFailedMessage:I,isAuthenticated:N,baseUrl:w,isTokenExpired:A,tokenExpiresIn:B,setToken:H,setRefreshTokenMarker:z,setSessionId:M,setBaseUrl:Q,setUserProfile:V,setupAutoRefresh:k,clearRefreshFailed:G,logout:O,initialize:K}}),ce="https://auth.eagleeyenetworks.com/oauth2/authorize";function b(){const e=x();if(!e)throw new Error("Client ID not configured. Call initEenToolkit() or set VITE_EEN_CLIENT_ID");const n=crypto.randomUUID();try{sessionStorage.setItem("een_oauth_state",n)}catch{}const t=new URLSearchParams({client_id:e,response_type:"code",scope:"vms.all",redirect_uri:$(),state:n});return c("Generated auth URL with state:",n),`${ce}?${t.toString()}`}async function D(e){const n=S();if(!n)return o("AUTH_FAILED","Proxy URL not configured. Call initEenToolkit() or set VITE_PROXY_URL");const t=new URLSearchParams({code:e,redirect_uri:$()});try{const r=await fetch(`${n}/proxy/getAccessToken?${t.toString()}`,{method:"POST",credentials:"include",headers:{Accept:"application/json"}});if(!r.ok){const i=await r.text().catch(()=>"Unknown error");return o("AUTH_FAILED",`Token exchange failed: ${i}`,r.status)}const a=await r.json();return c("Token received, expires in:",a.expiresIn),f(a)}catch(r){return o("NETWORK_ERROR",`Failed to exchange code: ${String(r)}`)}}async function P(){const e=S();if(!e)return o("AUTH_FAILED","Proxy URL not configured");const n=g();try{const t={Accept:"application/json"};n.sessionId&&(t.Authorization=`Bearer ${n.sessionId}`);const r=await fetch(`${e}/proxy/refreshAccessToken`,{method:"POST",credentials:"include",headers:t});if(!r.ok){const i=await r.text().catch(()=>"Unknown error");return o("AUTH_FAILED",`Token refresh failed: ${i}`,r.status)}const a=await r.json();return n.setToken(a.accessToken,a.expiresIn),c("Token refreshed, expires in:",a.expiresIn),f(a)}catch(t){return o("NETWORK_ERROR",`Failed to refresh token: ${String(t)}`)}}async function C(){const e=S();if(!e)return o("AUTH_FAILED","Proxy URL not configured");const n=g();try{const t={Accept:"application/json"};n.sessionId&&(t.Authorization=`Bearer ${n.sessionId}`);const r=await fetch(`${e}/proxy/revoke`,{method:"POST",credentials:"include",headers:t});if(n.logout(),!r.ok){const a=await r.text().catch(()=>"Unknown error");return o("AUTH_FAILED",`Token revocation failed: ${a}`,r.status)}return c("Token revoked"),f(void 0)}catch(t){return n.logout(),o("NETWORK_ERROR",`Failed to revoke token: ${String(t)}`)}}async function L(e,n){let t=null;try{t=sessionStorage.getItem("een_oauth_state"),sessionStorage.removeItem("een_oauth_state")}catch{}if(!t)return o("AUTH_FAILED","No OAuth state found. Please restart the login process.");if(!ue(n,t))return o("AUTH_FAILED","Invalid OAuth state. Possible CSRF attack.");c("State validated, exchanging code for token");const r=await D(e);if(r.error)return r;const a=g(),i=r.data;return a.setToken(i.accessToken,i.expiresIn),a.setRefreshTokenMarker("present"),a.setSessionId(i.sessionId),a.setBaseUrl(i.httpsBaseUrl),c("Auth callback complete, user:",i.userEmail),f(i)}function ue(e,n){if(e.length!==n.length)return!1;let t=0;for(let r=0;r<e.length;r++)t|=e.charCodeAt(r)^n.charCodeAt(r);return t===0}const le=Object.freeze(Object.defineProperty({__proto__:null,getAccessToken:D,getAuthUrl:b,handleAuthCallback:L,refreshToken:P,revokeToken:C},Symbol.toStringTag,{value:"Module"}));async function de(){const e=g();if(!e.isAuthenticated)return o("AUTH_REQUIRED","Authentication required");if(!e.baseUrl)return o("AUTH_REQUIRED","Base URL not configured");const n=`${e.baseUrl}/api/v3.0/users/self`;c("Fetching current user:",n);try{const t=await fetch(n,{method:"GET",headers:{Accept:"application/json",Authorization:`Bearer ${e.token}`}});if(!t.ok)return m(t);const r=await t.json();return c("Current user fetched:",r.email),e.setUserProfile(r),f(r)}catch(t){return o("NETWORK_ERROR",`Failed to fetch current user: ${String(t)}`)}}async function _e(e){const n=g();if(!n.isAuthenticated)return o("AUTH_REQUIRED","Authentication required");if(!n.baseUrl)return o("AUTH_REQUIRED","Base URL not configured");const t=new URLSearchParams;e?.pageSize&&t.append("pageSize",String(e.pageSize)),e?.pageToken&&t.append("pageToken",e.pageToken),e?.include&&e.include.length>0&&t.append("include",e.include.join(","));const r=t.toString(),a=`${n.baseUrl}/api/v3.0/users${r?`?${r}`:""}`;c("Fetching users:",a);try{const i=await fetch(a,{method:"GET",headers:{Accept:"application/json",Authorization:`Bearer ${n.token}`}});if(!i.ok)return m(i);const u=await i.json();return c("Users fetched:",u.results?.length??0,"users"),f(u)}catch(i){return o("NETWORK_ERROR",`Failed to fetch users: ${String(i)}`)}}async function fe(e,n){const t=g();if(!t.isAuthenticated)return o("AUTH_REQUIRED","Authentication required");if(!t.baseUrl)return o("AUTH_REQUIRED","Base URL not configured");if(!e)return o("VALIDATION_ERROR","User ID is required");const r=new URLSearchParams;n?.include&&n.include.length>0&&r.append("include",n.include.join(","));const a=r.toString(),i=`${t.baseUrl}/api/v3.0/users/${encodeURIComponent(e)}${a?`?${a}`:""}`;c("Fetching user:",i);try{const u=await fetch(i,{method:"GET",headers:{Accept:"application/json",Authorization:`Bearer ${t.token}`}});if(!u.ok)return m(u);const d=await u.json();return c("User fetched:",d.email),f(d)}catch(u){return o("NETWORK_ERROR",`Failed to fetch user: ${String(u)}`)}}async function m(e){const n=e.status;let t;try{const r=await e.json();t=r.message??r.error??e.statusText}catch{t=e.statusText||"Unknown error"}switch(n){case 401:return o("AUTH_REQUIRED",`Authentication failed: ${t}`,n);case 403:return o("FORBIDDEN",`Access denied: ${t}`,n);case 404:return o("NOT_FOUND",`Not found: ${t}`,n);case 429:return o("RATE_LIMITED",`Rate limited: ${t}`,n);default:return o("API_ERROR",`API error: ${t}`,n)}}async function ge(e){const n=g();if(!n.isAuthenticated)return o("AUTH_REQUIRED","Authentication required");if(!n.baseUrl)return o("AUTH_REQUIRED","Base URL not configured");const t=new URLSearchParams;e?.pageSize&&t.append("pageSize",String(e.pageSize)),e?.pageToken&&t.append("pageToken",e.pageToken),e?.include&&e.include.length>0&&t.append("include",e.include.join(",")),e?.sort&&e.sort.length>0&&t.append("sort",e.sort.join(",")),e?.locationId__in&&e.locationId__in.length>0&&t.append("locationId__in",e.locationId__in.join(",")),e?.bridgeId__in&&e.bridgeId__in.length>0&&t.append("bridgeId__in",e.bridgeId__in.join(",")),e?.multiCameraId&&t.append("multiCameraId",e.multiCameraId),e?.multiCameraId__ne&&t.append("multiCameraId__ne",e.multiCameraId__ne),e?.multiCameraId__in&&e.multiCameraId__in.length>0&&t.append("multiCameraId__in",e.multiCameraId__in.join(",")),e?.tags__contains&&e.tags__contains.length>0&&t.append("tags__contains",e.tags__contains.join(",")),e?.tags__any&&e.tags__any.length>0&&t.append("tags__any",e.tags__any.join(",")),e?.packages__contains&&e.packages__contains.length>0&&t.append("packages__contains",e.packages__contains.join(",")),e?.name&&t.append("name",e.name),e?.name__contains&&t.append("name__contains",e.name__contains),e?.name__in&&e.name__in.length>0&&t.append("name__in",e.name__in.join(",")),e?.id__in&&e.id__in.length>0&&t.append("id__in",e.id__in.join(",")),e?.id__notIn&&e.id__notIn.length>0&&t.append("id__notIn",e.id__notIn.join(",")),e?.id__contains&&t.append("id__contains",e.id__contains),e?.layoutId&&t.append("layoutId",e.layoutId),typeof e?.shared=="boolean"&&t.append("shareDetails.shared",String(e.shared)),e?.sharedCameraAccount&&t.append("shareDetails.accountId",e.sharedCameraAccount),typeof e?.firstResponder=="boolean"&&t.append("shareDetails.firstResponder",String(e.firstResponder)),typeof e?.directToCloud=="boolean"&&t.append("deviceInfo.directToCloud",String(e.directToCloud)),e?.speakerId__in&&e.speakerId__in.length>0&&t.append("speakerId__in",e.speakerId__in.join(",")),e?.q&&t.append("q",e.q),typeof e?.qRelevance__gte=="number"&&t.append("qRelevance__gte",String(e.qRelevance__gte)),e?.enabledAnalytics__contains&&e.enabledAnalytics__contains.length>0&&t.append("enabledAnalytics__contains",e.enabledAnalytics__contains.join(",")),e?.status__in&&e.status__in.length>0&&t.append("status__in",e.status__in.join(",")),e?.status__ne&&t.append("status__ne",e.status__ne);const r=t.toString(),a=`${n.baseUrl}/api/v3.0/cameras${r?`?${r}`:""}`;c("Fetching cameras:",a);try{const i=await fetch(a,{method:"GET",headers:{Accept:"application/json",Authorization:`Bearer ${n.token}`}});if(!i.ok)return F(i);const u=await i.json();return c("Cameras fetched:",u.results?.length??0,"cameras"),f(u)}catch(i){return o("NETWORK_ERROR",`Failed to fetch cameras: ${String(i)}`)}}async function he(e,n){const t=g();if(!t.isAuthenticated)return o("AUTH_REQUIRED","Authentication required");if(!t.baseUrl)return o("AUTH_REQUIRED","Base URL not configured");if(!e)return o("VALIDATION_ERROR","Camera ID is required");const r=new URLSearchParams;n?.include&&n.include.length>0&&r.append("include",n.include.join(","));const a=r.toString(),i=`${t.baseUrl}/api/v3.0/cameras/${encodeURIComponent(e)}${a?`?${a}`:""}`;c("Fetching camera:",i);try{const u=await fetch(i,{method:"GET",headers:{Accept:"application/json",Authorization:`Bearer ${t.token}`}});if(!u.ok)return F(u);const d=await u.json();return c("Camera fetched:",d.name),f(d)}catch(u){return o("NETWORK_ERROR",`Failed to fetch camera: ${String(u)}`)}}async function F(e){const n=e.status;let t;try{const r=await e.json();t=r.message??r.error??e.statusText}catch(r){c("Failed to parse error response JSON:",r),t=e.statusText||"Unknown error"}switch(n){case 401:return o("AUTH_REQUIRED",`Authentication failed: ${t}`,n);case 403:return o("FORBIDDEN",`Access denied: ${t}`,n);case 404:return o("NOT_FOUND",`Not found: ${t}`,n);case 429:return o("RATE_LIMITED",`Rate limited: ${t}`,n);default:return o("API_ERROR",`API error: ${t}`,n)}}async function Re(e){const n=g();if(!n.isAuthenticated)return o("AUTH_REQUIRED","Authentication required");if(!n.baseUrl)return o("AUTH_REQUIRED","Base URL not configured");const t=new URLSearchParams;e?.pageSize&&t.append("pageSize",String(e.pageSize)),e?.pageToken&&t.append("pageToken",e.pageToken),e?.include&&e.include.length>0&&t.append("include",e.include.join(",")),e?.sort&&e.sort.length>0&&t.append("sort",e.sort.join(",")),e?.locationId__in&&e.locationId__in.length>0&&t.append("locationId__in",e.locationId__in.join(",")),e?.tags__contains&&e.tags__contains.length>0&&t.append("tags__contains",e.tags__contains.join(",")),e?.tags__any&&e.tags__any.length>0&&t.append("tags__any",e.tags__any.join(",")),e?.name&&t.append("name",e.name),e?.name__contains&&t.append("name__contains",e.name__contains),e?.name__in&&e.name__in.length>0&&t.append("name__in",e.name__in.join(",")),e?.id__in&&e.id__in.length>0&&t.append("id__in",e.id__in.join(",")),e?.id__notIn&&e.id__notIn.length>0&&t.append("id__notIn",e.id__notIn.join(",")),e?.q&&t.append("q",e.q),typeof e?.qRelevance__gte=="number"&&t.append("qRelevance__gte",String(e.qRelevance__gte)),e?.status__in&&e.status__in.length>0&&t.append("status__in",e.status__in.join(",")),e?.status__ne&&t.append("status__ne",e.status__ne);const r=t.toString(),a=`${n.baseUrl}/api/v3.0/bridges${r?`?${r}`:""}`;c("Fetching bridges:",a);try{const i=await fetch(a,{method:"GET",headers:{Accept:"application/json",Authorization:`Bearer ${n.token}`}});if(!i.ok)return q(i);const u=await i.json();return c("Bridges fetched:",u.results?.length??0,"bridges"),f(u)}catch(i){return o("NETWORK_ERROR",`Failed to fetch bridges: ${String(i)}`)}}async function Ie(e,n){const t=g();if(!t.isAuthenticated)return o("AUTH_REQUIRED","Authentication required");if(!t.baseUrl)return o("AUTH_REQUIRED","Base URL not configured");if(!e)return o("VALIDATION_ERROR","Bridge ID is required");const r=new URLSearchParams;n?.include&&n.include.length>0&&r.append("include",n.include.join(","));const a=r.toString(),i=`${t.baseUrl}/api/v3.0/bridges/${encodeURIComponent(e)}${a?`?${a}`:""}`;c("Fetching bridge:",i);try{const u=await fetch(i,{method:"GET",headers:{Accept:"application/json",Authorization:`Bearer ${t.token}`}});if(!u.ok)return q(u);const d=await u.json();return c("Bridge fetched:",d.name),f(d)}catch(u){return o("NETWORK_ERROR",`Failed to fetch bridge: ${String(u)}`)}}async function q(e){const n=e.status;let t;try{const r=await e.json();t=r.message??r.error??e.statusText}catch(r){c("Failed to parse error response JSON:",r),t=e.statusText||"Unknown error"}switch(n){case 401:return o("AUTH_REQUIRED",`Authentication failed: ${t}`,n);case 403:return o("FORBIDDEN",`Access denied: ${t}`,n);case 404:return o("NOT_FOUND",`Not found: ${t}`,n);case 429:return o("RATE_LIMITED",`Rate limited: ${t}`,n);default:return o("API_ERROR",`API error: ${t}`,n)}}exports.failure=o;exports.getAccessToken=D;exports.getAuthUrl=b;exports.getBridge=Ie;exports.getBridges=Re;exports.getCamera=he;exports.getCameras=ge;exports.getClientId=x;exports.getConfig=oe;exports.getCurrentUser=de;exports.getProxyUrl=S;exports.getRedirectUri=$;exports.getUser=fe;exports.getUsers=_e;exports.handleAuthCallback=L;exports.initEenToolkit=re;exports.refreshToken=P;exports.revokeToken=C;exports.success=f;exports.useAuthStore=g;
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../src/config.ts","../src/types/common.ts","../src/utils/debug.ts","../src/auth/store.ts","../src/auth/service.ts","../src/users/service.ts","../src/cameras/service.ts"],"sourcesContent":["import type { EenToolkitConfig } from './types'\n\n/**\n * Global toolkit configuration\n */\nlet config: EenToolkitConfig = {}\n\n/**\n * Initialize the EEN API Toolkit\n */\nexport function initEenToolkit(options: EenToolkitConfig = {}): void {\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 debug: options.debug ?? import.meta.env?.VITE_DEBUG === 'true'\n }\n}\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 | '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 * 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 * 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 /** 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 * 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 { defineStore } from 'pinia'\nimport { ref, computed } from 'vue'\nimport type { UserProfile } from '../types'\nimport type { Result } from '../types'\nimport { debug } from '../utils/debug'\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\n function saveToStorage() {\n try {\n if (token.value) localStorage.setItem('een_token', token.value)\n if (tokenExpiration.value) localStorage.setItem('een_tokenExpiration', String(tokenExpiration.value))\n if (refreshTokenMarker.value) localStorage.setItem('een_refreshTokenMarker', refreshTokenMarker.value)\n if (sessionId.value) localStorage.setItem('een_sessionId', sessionId.value)\n if (hostname.value) localStorage.setItem('een_hostname', hostname.value)\n if (port.value !== 443) localStorage.setItem('een_port', String(port.value))\n if (userProfile.value) localStorage.setItem('een_userProfile', JSON.stringify(userProfile.value))\n } catch (err: unknown) {\n // localStorage might not be available (SSR, private browsing, etc.)\n debug('Failed to save to localStorage:', err instanceof Error ? err.message : String(err))\n }\n }\n\n function loadFromStorage() {\n try {\n token.value = localStorage.getItem('een_token')\n const expStr = localStorage.getItem('een_tokenExpiration')\n tokenExpiration.value = expStr ? parseInt(expStr, 10) : null\n refreshTokenMarker.value = localStorage.getItem('een_refreshTokenMarker')\n sessionId.value = localStorage.getItem('een_sessionId')\n hostname.value = localStorage.getItem('een_hostname')\n const portStr = localStorage.getItem('een_port')\n port.value = portStr ? parseInt(portStr, 10) : 443\n const profileStr = localStorage.getItem('een_userProfile')\n userProfile.value = profileStr ? JSON.parse(profileStr) : null\n } catch (err: unknown) {\n // localStorage might not be available (SSR, private browsing, etc.)\n debug('Failed to load from localStorage:', err instanceof Error ? err.message : String(err))\n }\n }\n\n function clearStorage() {\n try {\n localStorage.removeItem('een_token')\n localStorage.removeItem('een_tokenExpiration')\n localStorage.removeItem('een_refreshTokenMarker')\n localStorage.removeItem('een_sessionId')\n localStorage.removeItem('een_hostname')\n localStorage.removeItem('een_port')\n localStorage.removeItem('een_userProfile')\n } catch (err: unknown) {\n // localStorage might not be available (SSR, private browsing, etc.)\n debug('Failed to clear localStorage:', 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/listusers).\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"],"names":["config","initEenToolkit","options","__vite_import_meta_env__","getConfig","getProxyUrl","getClientId","getRedirectUri","success","data","failure","code","message","status","details","isDebugEnabled","debug","args","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","i","getCurrentUser","handleErrorResponse","getUsers","queryParams","queryString","getUser","userId","errorData","getCameras","getCamera","cameraId","parseError"],"mappings":"gIAKA,IAAIA,EAA2B,CAAA,EAKxB,SAASC,GAAeC,EAA4B,GAAU,CACnEF,EAAS,CACP,SAAUE,EAAQ,UAAYC,GAAiB,eAC/C,SAAUD,EAAQ,UAAYC,GAAiB,mBAC/C,YAAaD,EAAQ,aAAeC,GAAiB,kBACrD,MAAOD,EAAQ,OAASC,GAAiB,aAAe,MAAA,CAE5D,CAKO,SAASC,IAA8B,CAC5C,OAAOJ,CACT,CAKO,SAASK,GAAkC,CAChD,OAAOL,EAAO,UAAYG,GAAiB,cAC7C,CAKO,SAASG,GAAkC,CAChD,OAAON,EAAO,UAAYG,GAAiB,kBAC7C,CAKO,SAASI,GAAyB,CACvC,OAAOP,EAAO,aAAeG,GAAiB,mBAAqB,uBACrE,CCgIO,SAASK,EAAWC,EAAoB,CAC7C,MAAO,CAAE,KAAAA,EAAM,MAAO,IAAA,CACxB,CAaO,SAASC,EAAWC,EAAiBC,EAAiBC,EAAiBC,EAA8B,CAC1G,MAAO,CAAE,KAAM,KAAM,MAAO,CAAE,KAAAH,EAAM,QAAAC,EAAS,OAAAC,EAAQ,QAAAC,EAAQ,CAC/D,iECzLMC,GAAiB,IAAe,CACpC,GAAI,CACF,OAAOZ,IAAiB,aAAe,MACzC,MAAQ,CACN,MAAO,EACT,CACF,EAEO,SAASa,KAASC,EAAuB,CAC1CF,MACF,QAAQ,IAAI,oBAAqB,GAAGE,CAAI,CAE5C,CCTA,IAAIC,EAA2G,KAE/G,SAASC,IAAoB,CAC3B,OAAKD,IACHA,EAAwB,QAAA,QAAA,EAAA,KAAA,IAAAE,EAAA,EAAoB,KAAMA,GAAYA,EAAQ,YAAY,GAE7EF,CACT,CAKO,MAAMG,EAAeC,GAAAA,YAAY,WAAY,IAAM,CAExD,MAAMC,EAAQC,EAAAA,IAAmB,IAAI,EAC/BC,EAAkBD,EAAAA,IAAmB,IAAI,EACzCE,EAAqBF,EAAAA,IAAmB,IAAI,EAC5CG,EAAYH,EAAAA,IAAmB,IAAI,EACnCI,EAAWJ,EAAAA,IAAmB,IAAI,EAClCK,EAAOL,EAAAA,IAAY,GAAG,EACtBM,EAAcN,EAAAA,IAAwB,IAAI,EAC1CO,EAAiBP,EAAAA,IAA0C,IAAI,EAC/DQ,EAAeR,EAAAA,IAAI,EAAK,EAC9B,IAAIS,EAAuC,KAC3C,MAAMC,EAAgBV,EAAAA,IAAI,EAAK,EACzBW,EAAuBX,EAAAA,IAAmB,IAAI,EAG9CY,EAAkBC,EAAAA,SAAS,IAAM,CAAC,CAACd,EAAM,KAAK,EAE9Ce,EAAUD,EAAAA,SAAS,IAClBT,EAAS,MACPC,EAAK,QAAU,IAClB,WAAWD,EAAS,KAAK,GACzB,WAAWA,EAAS,KAAK,IAAIC,EAAK,KAAK,GAHf,IAI7B,EAEKU,EAAiBF,EAAAA,SAAS,IACzBZ,EAAgB,MACd,KAAK,OAASA,EAAgB,MADF,EAEpC,EAEKe,EAAiBH,EAAAA,SAAS,IACzBZ,EAAgB,MACd,KAAK,IAAI,EAAGA,EAAgB,MAAQ,KAAK,KAAK,EADlB,CAEpC,EAGD,SAASgB,EAASC,EAAkBC,EAAmB,CACrDpB,EAAM,MAAQmB,EACdjB,EAAgB,MAAQ,KAAK,IAAA,EAAQkB,EAAY,IACjDC,EAAA,EACAC,EAAA,EACA7B,EAAM,wBAAyB2B,EAAW,SAAS,CACrD,CAEA,SAASG,EAAsBC,EAAgB,CAC7CrB,EAAmB,MAAQqB,EAC3BH,EAAA,CACF,CAEA,SAASI,EAAaC,EAAsB,CAC1CtB,EAAU,MAAQsB,EAClBL,EAAA,CACF,CAEA,SAASM,EAAWzC,EAAoD,CACtE,GAAI,OAAOA,GAAS,SAElB,GAAI,CACF,MAAM0C,EAAM,IAAI,IAAI1C,EAAK,WAAW,MAAM,EAAIA,EAAO,WAAWA,CAAI,EAAE,EACtEmB,EAAS,MAAQuB,EAAI,SACrBtB,EAAK,MAAQsB,EAAI,KAAO,SAASA,EAAI,KAAM,EAAE,EAAI,GACnD,OAASC,EAAc,CAErBpC,EAAM,0CAA2CoC,aAAe,MAAQA,EAAI,QAAU,OAAOA,CAAG,CAAC,EACjGxB,EAAS,MAAQnB,EACjBoB,EAAK,MAAQ,GACf,MAEAD,EAAS,MAAQnB,EAAK,SACtBoB,EAAK,MAAQpB,EAAK,MAAQ,IAE5BmC,EAAA,EACA5B,EAAM,gBAAiBsB,EAAQ,KAAK,CACtC,CAEA,SAASe,EAAeC,EAAsB,CAC5CxB,EAAY,MAAQwB,EACpBV,EAAA,CACF,CAEA,SAASC,GAAmB,CAO1B,GALId,EAAe,QACjB,aAAaA,EAAe,KAAK,EACjCA,EAAe,MAAQ,MAGrB,CAACN,EAAgB,OAAS,CAACF,EAAM,MACnC,OAGF,MAAMgC,EAAM,KAAK,IAAA,EAEXC,EADY/B,EAAgB,MACE8B,EAI9BE,EAAc,IAAS,IACvBC,EAAUF,EAAkB,EAC5BG,EAAgB,KAAK,IAAIF,EAAaC,CAAO,EAC7CE,GAAc,KAAK,IAAIJ,EAAkBG,EAAe,GAAK,GAAI,EACjEE,EAAU,KAAK,IAAID,GAAa,GAAI,EAE1C5C,EAAM,4BAA6B,KAAK,MAAM6C,EAAU,GAAI,EAAG,SAAS,EAExE9B,EAAe,MAAQ,WAAW,SAAY,CAC5C,MAAM+B,EAAA,CACR,EAAGD,CAAO,CACZ,CAEA,eAAeC,GAAoC,CAEjD,OAAI7B,GACFjB,EAAM,2DAA2D,EAC1DiB,IAGTD,EAAa,MAAQ,GACrBhB,EAAM,yBAAyB,EAE/BiB,GAAkB,SAAY,CAC5B,GAAI,CAEF,MAAM8B,EAAS,MADM,MAAM5C,GAAA,GACN,EAEjB4C,EAAO,OACT7B,EAAc,MAAQ,GACtBC,EAAqB,MAAQ4B,EAAO,MAAM,QAC1C/C,EAAM,uBAAwB+C,EAAO,MAAM,OAAO,IAElD7B,EAAc,MAAQ,GACtBC,EAAqB,MAAQ,KAC7BnB,EAAM,yBAAyB,EAEnC,OAASoC,EAAc,CACrBlB,EAAc,MAAQ,GACtBC,EAAqB,MAAQiB,aAAe,MAAQA,EAAI,QAAU,OAAOA,CAAG,EAC5EpC,EAAM,sBAAuBoC,CAAG,CAClC,QAAA,CACEpB,EAAa,MAAQ,GACrBC,EAAiB,IACnB,CACF,GAAA,EAEOA,EACT,CAEA,SAAS+B,GAAqB,CAC5B9B,EAAc,MAAQ,GACtBC,EAAqB,MAAQ,IAC/B,CAEA,SAAS8B,GAAS,CAEZlC,EAAe,QACjB,aAAaA,EAAe,KAAK,EACjCA,EAAe,MAAQ,MAIzBR,EAAM,MAAQ,KACdE,EAAgB,MAAQ,KACxBC,EAAmB,MAAQ,KAC3BC,EAAU,MAAQ,KAClBC,EAAS,MAAQ,KACjBC,EAAK,MAAQ,IACbC,EAAY,MAAQ,KACpBI,EAAc,MAAQ,GACtBC,EAAqB,MAAQ,KAG7B+B,EAAA,EACAlD,EAAM,YAAY,CACpB,CAEA,SAASmD,GAAa,CACpBC,EAAA,EACI7C,EAAM,OAAS,CAACgB,EAAe,OACjCM,EAAA,EACA7B,EAAM,0BAA0B,GACvBO,EAAM,OAASgB,EAAe,QACvCvB,EAAM,gCAAgC,EACtCiD,EAAA,EAEJ,CAGA,SAASrB,GAAgB,CACvB,GAAI,CACErB,EAAM,OAAO,aAAa,QAAQ,YAAaA,EAAM,KAAK,EAC1DE,EAAgB,OAAO,aAAa,QAAQ,sBAAuB,OAAOA,EAAgB,KAAK,CAAC,EAChGC,EAAmB,OAAO,aAAa,QAAQ,yBAA0BA,EAAmB,KAAK,EACjGC,EAAU,OAAO,aAAa,QAAQ,gBAAiBA,EAAU,KAAK,EACtEC,EAAS,OAAO,aAAa,QAAQ,eAAgBA,EAAS,KAAK,EACnEC,EAAK,QAAU,KAAK,aAAa,QAAQ,WAAY,OAAOA,EAAK,KAAK,CAAC,EACvEC,EAAY,OAAO,aAAa,QAAQ,kBAAmB,KAAK,UAAUA,EAAY,KAAK,CAAC,CAClG,OAASsB,EAAc,CAErBpC,EAAM,kCAAmCoC,aAAe,MAAQA,EAAI,QAAU,OAAOA,CAAG,CAAC,CAC3F,CACF,CAEA,SAASgB,GAAkB,CACzB,GAAI,CACF7C,EAAM,MAAQ,aAAa,QAAQ,WAAW,EAC9C,MAAM8C,EAAS,aAAa,QAAQ,qBAAqB,EACzD5C,EAAgB,MAAQ4C,EAAS,SAASA,EAAQ,EAAE,EAAI,KACxD3C,EAAmB,MAAQ,aAAa,QAAQ,wBAAwB,EACxEC,EAAU,MAAQ,aAAa,QAAQ,eAAe,EACtDC,EAAS,MAAQ,aAAa,QAAQ,cAAc,EACpD,MAAM0C,EAAU,aAAa,QAAQ,UAAU,EAC/CzC,EAAK,MAAQyC,EAAU,SAASA,EAAS,EAAE,EAAI,IAC/C,MAAMC,EAAa,aAAa,QAAQ,iBAAiB,EACzDzC,EAAY,MAAQyC,EAAa,KAAK,MAAMA,CAAU,EAAI,IAC5D,OAASnB,EAAc,CAErBpC,EAAM,oCAAqCoC,aAAe,MAAQA,EAAI,QAAU,OAAOA,CAAG,CAAC,CAC7F,CACF,CAEA,SAASc,GAAe,CACtB,GAAI,CACF,aAAa,WAAW,WAAW,EACnC,aAAa,WAAW,qBAAqB,EAC7C,aAAa,WAAW,wBAAwB,EAChD,aAAa,WAAW,eAAe,EACvC,aAAa,WAAW,cAAc,EACtC,aAAa,WAAW,UAAU,EAClC,aAAa,WAAW,iBAAiB,CAC3C,OAASd,EAAc,CAErBpC,EAAM,gCAAiCoC,aAAe,MAAQA,EAAI,QAAU,OAAOA,CAAG,CAAC,CACzF,CACF,CAEA,MAAO,CAEL,MAAA7B,EACA,gBAAAE,EACA,mBAAAC,EACA,UAAAC,EACA,SAAAC,EACA,KAAAC,EACA,YAAAC,EACA,aAAAE,EACA,cAAAE,EACA,qBAAAC,EAGA,gBAAAC,EACA,QAAAE,EACA,eAAAC,EACA,eAAAC,EAGA,SAAAC,EACA,sBAAAK,EACA,aAAAE,EACA,WAAAE,EACA,eAAAG,EACA,iBAAAR,EACA,mBAAAmB,EACA,OAAAC,EACA,WAAAE,CAAA,CAEJ,CAAC,ECvRKK,GAAe,qDAsBd,SAASC,GAAqB,CACnC,MAAMC,EAAWpE,EAAA,EACjB,GAAI,CAACoE,EACH,MAAM,IAAI,MAAM,2EAA2E,EAI7F,MAAMC,EAAQ,OAAO,WAAA,EACrB,GAAI,CACF,eAAe,QAAQ,kBAAmBA,CAAK,CACjD,MAAQ,CAER,CAEA,MAAMC,EAAS,IAAI,gBAAgB,CACjC,UAAWF,EACX,cAAe,OACf,MAAO,UACP,aAAcnE,EAAA,EACd,MAAAoE,CAAA,CACD,EAED,OAAA3D,EAAM,iCAAkC2D,CAAK,EACtC,GAAGH,EAAY,IAAII,EAAO,UAAU,EAC7C,CAKA,eAAsBC,EAAelE,EAA8C,CACjF,MAAMmE,EAAWzE,EAAA,EACjB,GAAI,CAACyE,EACH,OAAOpE,EAAQ,cAAe,uEAAuE,EAGvG,MAAMkE,EAAS,IAAI,gBAAgB,CACjC,KAAAjE,EACA,aAAcJ,EAAA,CAAe,CAC9B,EAED,GAAI,CACF,MAAMwE,EAAW,MAAM,MAAM,GAAGD,CAAQ,yBAAyBF,EAAO,SAAA,CAAU,GAAI,CACpF,OAAQ,OACR,YAAa,UACb,QAAS,CACP,OAAU,kBAAA,CACZ,CACD,EAED,GAAI,CAACG,EAAS,GAAI,CAChB,MAAMC,EAAY,MAAMD,EAAS,OAAO,MAAM,IAAM,eAAe,EACnE,OAAOrE,EAAQ,cAAe,0BAA0BsE,CAAS,GAAID,EAAS,MAAM,CACtF,CAEA,MAAMtE,EAAO,MAAMsE,EAAS,KAAA,EAC5B,OAAA/D,EAAM,8BAA+BP,EAAK,SAAS,EAC5CD,EAAQC,CAAI,CACrB,OAAS2C,EAAK,CACZ,OAAO1C,EAAQ,gBAAiB,4BAA4B,OAAO0C,CAAG,CAAC,EAAE,CAC3E,CACF,CAKA,eAAsB6B,GAA4E,CAChG,MAAMH,EAAWzE,EAAA,EACjB,GAAI,CAACyE,EACH,OAAOpE,EAAQ,cAAe,0BAA0B,EAG1D,MAAMwE,EAAY7D,EAAA,EAElB,GAAI,CACF,MAAM8D,EAAuB,CAC3B,OAAU,kBAAA,EAIRD,EAAU,YACZC,EAAQ,cAAmB,UAAUD,EAAU,SAAS,IAG1D,MAAMH,EAAW,MAAM,MAAM,GAAGD,CAAQ,4BAA6B,CACnE,OAAQ,OACR,YAAa,UACb,QAAAK,CAAA,CACD,EAED,GAAI,CAACJ,EAAS,GAAI,CAChB,MAAMC,EAAY,MAAMD,EAAS,OAAO,MAAM,IAAM,eAAe,EACnE,OAAOrE,EAAQ,cAAe,yBAAyBsE,CAAS,GAAID,EAAS,MAAM,CACrF,CAEA,MAAMtE,EAAO,MAAMsE,EAAS,KAAA,EAG5B,OAAAG,EAAU,SAASzE,EAAK,YAAaA,EAAK,SAAS,EAEnDO,EAAM,+BAAgCP,EAAK,SAAS,EAC7CD,EAAQC,CAAI,CACrB,OAAS2C,EAAK,CACZ,OAAO1C,EAAQ,gBAAiB,4BAA4B,OAAO0C,CAAG,CAAC,EAAE,CAC3E,CACF,CAKA,eAAsBgC,GAAqC,CACzD,MAAMN,EAAWzE,EAAA,EACjB,GAAI,CAACyE,EACH,OAAOpE,EAAQ,cAAe,0BAA0B,EAG1D,MAAMwE,EAAY7D,EAAA,EAElB,GAAI,CACF,MAAM8D,EAAuB,CAC3B,OAAU,kBAAA,EAGRD,EAAU,YACZC,EAAQ,cAAmB,UAAUD,EAAU,SAAS,IAG1D,MAAMH,EAAW,MAAM,MAAM,GAAGD,CAAQ,gBAAiB,CACvD,OAAQ,OACR,YAAa,UACb,QAAAK,CAAA,CACD,EAKD,GAFAD,EAAU,OAAA,EAEN,CAACH,EAAS,GAAI,CAChB,MAAMC,EAAY,MAAMD,EAAS,OAAO,MAAM,IAAM,eAAe,EACnE,OAAOrE,EAAQ,cAAe,4BAA4BsE,CAAS,GAAID,EAAS,MAAM,CACxF,CAEA,OAAA/D,EAAM,eAAe,EACdR,EAAQ,MAAS,CAC1B,OAAS4C,EAAK,CAEZ,OAAA8B,EAAU,OAAA,EACHxE,EAAQ,gBAAiB,2BAA2B,OAAO0C,CAAG,CAAC,EAAE,CAC1E,CACF,CAKA,eAAsBiC,EAAmB1E,EAAcgE,EAA+C,CAEpG,IAAIW,EAA6B,KACjC,GAAI,CACFA,EAAc,eAAe,QAAQ,iBAAiB,EACtD,eAAe,WAAW,iBAAiB,CAC7C,MAAQ,CAER,CAEA,GAAI,CAACA,EACH,OAAO5E,EAAQ,cAAe,yDAAyD,EAIzF,GAAI,CAAC6E,GAAmBZ,EAAOW,CAAW,EACxC,OAAO5E,EAAQ,cAAe,4CAA4C,EAG5EM,EAAM,4CAA4C,EAGlD,MAAM+C,EAAS,MAAMc,EAAelE,CAAI,EAExC,GAAIoD,EAAO,MACT,OAAOA,EAIT,MAAMmB,EAAY7D,EAAA,EACZZ,EAAOsD,EAAO,KAEpB,OAAAmB,EAAU,SAASzE,EAAK,YAAaA,EAAK,SAAS,EACnDyE,EAAU,sBAAsB,SAAS,EACzCA,EAAU,aAAazE,EAAK,SAAS,EACrCyE,EAAU,WAAWzE,EAAK,YAAY,EAEtCO,EAAM,gCAAiCP,EAAK,SAAS,EAE9CD,EAAQC,CAAI,CACrB,CAKA,SAAS8E,GAAmBC,EAAWC,EAAoB,CACzD,GAAID,EAAE,SAAWC,EAAE,OACjB,MAAO,GAGT,IAAI1B,EAAS,EACb,QAAS2B,EAAI,EAAGA,EAAIF,EAAE,OAAQE,IAC5B3B,GAAUyB,EAAE,WAAWE,CAAC,EAAID,EAAE,WAAWC,CAAC,EAG5C,OAAO3B,IAAW,CACpB,qLC5MA,eAAsB4B,IAA+C,CACnE,MAAMT,EAAY7D,EAAA,EAElB,GAAI,CAAC6D,EAAU,gBACb,OAAOxE,EAAQ,gBAAiB,yBAAyB,EAG3D,GAAI,CAACwE,EAAU,QACb,OAAOxE,EAAQ,gBAAiB,yBAAyB,EAG3D,MAAMyC,EAAM,GAAG+B,EAAU,OAAO,uBAChClE,EAAM,yBAA0BmC,CAAG,EAEnC,GAAI,CACF,MAAM4B,EAAW,MAAM,MAAM5B,EAAK,CAChC,OAAQ,MACR,QAAS,CACP,OAAU,mBACV,cAAiB,UAAU+B,EAAU,KAAK,EAAA,CAC5C,CACD,EAED,GAAI,CAACH,EAAS,GACZ,OAAOa,EAAoBb,CAAQ,EAGrC,MAAMtE,EAAO,MAAMsE,EAAS,KAAA,EAC5B,OAAA/D,EAAM,wBAAyBP,EAAK,KAAK,EAGzCyE,EAAU,eAAezE,CAAI,EAEtBD,EAAQC,CAAI,CACrB,OAAS2C,EAAK,CACZ,OAAO1C,EAAQ,gBAAiB,iCAAiC,OAAO0C,CAAG,CAAC,EAAE,CAChF,CACF,CAgDA,eAAsByC,GAASjB,EAAkE,CAC/F,MAAMM,EAAY7D,EAAA,EAElB,GAAI,CAAC6D,EAAU,gBACb,OAAOxE,EAAQ,gBAAiB,yBAAyB,EAG3D,GAAI,CAACwE,EAAU,QACb,OAAOxE,EAAQ,gBAAiB,yBAAyB,EAG3D,MAAMoF,EAAc,IAAI,gBAEpBlB,GAAQ,UACVkB,EAAY,OAAO,WAAY,OAAOlB,EAAO,QAAQ,CAAC,EAEpDA,GAAQ,WACVkB,EAAY,OAAO,YAAalB,EAAO,SAAS,EAE9CA,GAAQ,SAAWA,EAAO,QAAQ,OAAS,GAC7CkB,EAAY,OAAO,UAAWlB,EAAO,QAAQ,KAAK,GAAG,CAAC,EAGxD,MAAMmB,EAAcD,EAAY,SAAA,EAC1B3C,EAAM,GAAG+B,EAAU,OAAO,kBAAkBa,EAAc,IAAIA,CAAW,GAAK,EAAE,GACtF/E,EAAM,kBAAmBmC,CAAG,EAE5B,GAAI,CACF,MAAM4B,EAAW,MAAM,MAAM5B,EAAK,CAChC,OAAQ,MACR,QAAS,CACP,OAAU,mBACV,cAAiB,UAAU+B,EAAU,KAAK,EAAA,CAC5C,CACD,EAED,GAAI,CAACH,EAAS,GACZ,OAAOa,EAAoBb,CAAQ,EAGrC,MAAMtE,EAAO,MAAMsE,EAAS,KAAA,EAC5B,OAAA/D,EAAM,iBAAkBP,EAAK,SAAS,QAAU,EAAG,OAAO,EAEnDD,EAAQC,CAAI,CACrB,OAAS2C,EAAK,CACZ,OAAO1C,EAAQ,gBAAiB,0BAA0B,OAAO0C,CAAG,CAAC,EAAE,CACzE,CACF,CAwCA,eAAsB4C,GAAQC,EAAgBrB,EAA+C,CAC3F,MAAMM,EAAY7D,EAAA,EAElB,GAAI,CAAC6D,EAAU,gBACb,OAAOxE,EAAQ,gBAAiB,yBAAyB,EAG3D,GAAI,CAACwE,EAAU,QACb,OAAOxE,EAAQ,gBAAiB,yBAAyB,EAG3D,GAAI,CAACuF,EACH,OAAOvF,EAAQ,mBAAoB,qBAAqB,EAG1D,MAAMoF,EAAc,IAAI,gBAEpBlB,GAAQ,SAAWA,EAAO,QAAQ,OAAS,GAC7CkB,EAAY,OAAO,UAAWlB,EAAO,QAAQ,KAAK,GAAG,CAAC,EAGxD,MAAMmB,EAAcD,EAAY,SAAA,EAC1B3C,EAAM,GAAG+B,EAAU,OAAO,mBAAmB,mBAAmBe,CAAM,CAAC,GAAGF,EAAc,IAAIA,CAAW,GAAK,EAAE,GACpH/E,EAAM,iBAAkBmC,CAAG,EAE3B,GAAI,CACF,MAAM4B,EAAW,MAAM,MAAM5B,EAAK,CAChC,OAAQ,MACR,QAAS,CACP,OAAU,mBACV,cAAiB,UAAU+B,EAAU,KAAK,EAAA,CAC5C,CACD,EAED,GAAI,CAACH,EAAS,GACZ,OAAOa,EAAoBb,CAAQ,EAGrC,MAAMtE,EAAO,MAAMsE,EAAS,KAAA,EAC5B,OAAA/D,EAAM,gBAAiBP,EAAK,KAAK,EAE1BD,EAAQC,CAAI,CACrB,OAAS2C,EAAK,CACZ,OAAO1C,EAAQ,gBAAiB,yBAAyB,OAAO0C,CAAG,CAAC,EAAE,CACxE,CACF,CAMA,eAAewC,EAAuBb,EAAwC,CAC5E,MAAMlE,EAASkE,EAAS,OAExB,IAAInE,EACJ,GAAI,CACF,MAAMsF,EAAY,MAAMnB,EAAS,KAAA,EACjCnE,EAAUsF,EAAU,SAAWA,EAAU,OAASnB,EAAS,UAC7D,MAAQ,CACNnE,EAAUmE,EAAS,YAAc,eACnC,CAEA,OAAQlE,EAAA,CACN,IAAK,KACH,OAAOH,EAAQ,gBAAiB,0BAA0BE,CAAO,GAAIC,CAAM,EAC7E,IAAK,KACH,OAAOH,EAAQ,YAAa,kBAAkBE,CAAO,GAAIC,CAAM,EACjE,IAAK,KACH,OAAOH,EAAQ,YAAa,cAAcE,CAAO,GAAIC,CAAM,EAC7D,IAAK,KACH,OAAOH,EAAQ,eAAgB,iBAAiBE,CAAO,GAAIC,CAAM,EACnE,QACE,OAAOH,EAAQ,YAAa,cAAcE,CAAO,GAAIC,CAAM,CAAA,CAEjE,CCtOA,eAAsBsF,GAAWvB,EAAsE,CACrG,MAAMM,EAAY7D,EAAA,EAElB,GAAI,CAAC6D,EAAU,gBACb,OAAOxE,EAAQ,gBAAiB,yBAAyB,EAG3D,GAAI,CAACwE,EAAU,QACb,OAAOxE,EAAQ,gBAAiB,yBAAyB,EAG3D,MAAMoF,EAAc,IAAI,gBAGpBlB,GAAQ,UACVkB,EAAY,OAAO,WAAY,OAAOlB,EAAO,QAAQ,CAAC,EAEpDA,GAAQ,WACVkB,EAAY,OAAO,YAAalB,EAAO,SAAS,EAI9CA,GAAQ,SAAWA,EAAO,QAAQ,OAAS,GAC7CkB,EAAY,OAAO,UAAWlB,EAAO,QAAQ,KAAK,GAAG,CAAC,EAEpDA,GAAQ,MAAQA,EAAO,KAAK,OAAS,GACvCkB,EAAY,OAAO,OAAQlB,EAAO,KAAK,KAAK,GAAG,CAAC,EAI9CA,GAAQ,gBAAkBA,EAAO,eAAe,OAAS,GAC3DkB,EAAY,OAAO,iBAAkBlB,EAAO,eAAe,KAAK,GAAG,CAAC,EAElEA,GAAQ,cAAgBA,EAAO,aAAa,OAAS,GACvDkB,EAAY,OAAO,eAAgBlB,EAAO,aAAa,KAAK,GAAG,CAAC,EAI9DA,GAAQ,eACVkB,EAAY,OAAO,gBAAiBlB,EAAO,aAAa,EAEtDA,GAAQ,mBACVkB,EAAY,OAAO,oBAAqBlB,EAAO,iBAAiB,EAE9DA,GAAQ,mBAAqBA,EAAO,kBAAkB,OAAS,GACjEkB,EAAY,OAAO,oBAAqBlB,EAAO,kBAAkB,KAAK,GAAG,CAAC,EAIxEA,GAAQ,gBAAkBA,EAAO,eAAe,OAAS,GAC3DkB,EAAY,OAAO,iBAAkBlB,EAAO,eAAe,KAAK,GAAG,CAAC,EAElEA,GAAQ,WAAaA,EAAO,UAAU,OAAS,GACjDkB,EAAY,OAAO,YAAalB,EAAO,UAAU,KAAK,GAAG,CAAC,EAExDA,GAAQ,oBAAsBA,EAAO,mBAAmB,OAAS,GACnEkB,EAAY,OAAO,qBAAsBlB,EAAO,mBAAmB,KAAK,GAAG,CAAC,EAI1EA,GAAQ,MACVkB,EAAY,OAAO,OAAQlB,EAAO,IAAI,EAEpCA,GAAQ,gBACVkB,EAAY,OAAO,iBAAkBlB,EAAO,cAAc,EAExDA,GAAQ,UAAYA,EAAO,SAAS,OAAS,GAC/CkB,EAAY,OAAO,WAAYlB,EAAO,SAAS,KAAK,GAAG,CAAC,EAItDA,GAAQ,QAAUA,EAAO,OAAO,OAAS,GAC3CkB,EAAY,OAAO,SAAUlB,EAAO,OAAO,KAAK,GAAG,CAAC,EAElDA,GAAQ,WAAaA,EAAO,UAAU,OAAS,GACjDkB,EAAY,OAAO,YAAalB,EAAO,UAAU,KAAK,GAAG,CAAC,EAExDA,GAAQ,cACVkB,EAAY,OAAO,eAAgBlB,EAAO,YAAY,EAIpDA,GAAQ,UACVkB,EAAY,OAAO,WAAYlB,EAAO,QAAQ,EAI5C,OAAOA,GAAQ,QAAW,WAC5BkB,EAAY,OAAO,sBAAuB,OAAOlB,EAAO,MAAM,CAAC,EAE7DA,GAAQ,qBACVkB,EAAY,OAAO,yBAA0BlB,EAAO,mBAAmB,EAErE,OAAOA,GAAQ,gBAAmB,WACpCkB,EAAY,OAAO,8BAA+B,OAAOlB,EAAO,cAAc,CAAC,EAI7E,OAAOA,GAAQ,eAAkB,WACnCkB,EAAY,OAAO,2BAA4B,OAAOlB,EAAO,aAAa,CAAC,EAIzEA,GAAQ,eAAiBA,EAAO,cAAc,OAAS,GACzDkB,EAAY,OAAO,gBAAiBlB,EAAO,cAAc,KAAK,GAAG,CAAC,EAIhEA,GAAQ,GACVkB,EAAY,OAAO,IAAKlB,EAAO,CAAC,EAE9B,OAAOA,GAAQ,iBAAoB,UACrCkB,EAAY,OAAO,kBAAmB,OAAOlB,EAAO,eAAe,CAAC,EAIlEA,GAAQ,4BAA8BA,EAAO,2BAA2B,OAAS,GACnFkB,EAAY,OAAO,6BAA8BlB,EAAO,2BAA2B,KAAK,GAAG,CAAC,EAI1FA,GAAQ,YAAcA,EAAO,WAAW,OAAS,GACnDkB,EAAY,OAAO,aAAclB,EAAO,WAAW,KAAK,GAAG,CAAC,EAE1DA,GAAQ,YACVkB,EAAY,OAAO,aAAclB,EAAO,UAAU,EAGpD,MAAMmB,EAAcD,EAAY,SAAA,EAC1B3C,EAAM,GAAG+B,EAAU,OAAO,oBAAoBa,EAAc,IAAIA,CAAW,GAAK,EAAE,GACxF/E,EAAM,oBAAqBmC,CAAG,EAE9B,GAAI,CACF,MAAM4B,EAAW,MAAM,MAAM5B,EAAK,CAChC,OAAQ,MACR,QAAS,CACP,OAAU,mBACV,cAAiB,UAAU+B,EAAU,KAAK,EAAA,CAC5C,CACD,EAED,GAAI,CAACH,EAAS,GACZ,OAAOa,EAAoBb,CAAQ,EAGrC,MAAMtE,EAAO,MAAMsE,EAAS,KAAA,EAC5B,OAAA/D,EAAM,mBAAoBP,EAAK,SAAS,QAAU,EAAG,SAAS,EAEvDD,EAAQC,CAAI,CACrB,OAAS2C,EAAK,CACZ,OAAO1C,EAAQ,gBAAiB,4BAA4B,OAAO0C,CAAG,CAAC,EAAE,CAC3E,CACF,CAuCA,eAAsBgD,GAAUC,EAAkBzB,EAAmD,CACnG,MAAMM,EAAY7D,EAAA,EAElB,GAAI,CAAC6D,EAAU,gBACb,OAAOxE,EAAQ,gBAAiB,yBAAyB,EAG3D,GAAI,CAACwE,EAAU,QACb,OAAOxE,EAAQ,gBAAiB,yBAAyB,EAG3D,GAAI,CAAC2F,EACH,OAAO3F,EAAQ,mBAAoB,uBAAuB,EAG5D,MAAMoF,EAAc,IAAI,gBAEpBlB,GAAQ,SAAWA,EAAO,QAAQ,OAAS,GAC7CkB,EAAY,OAAO,UAAWlB,EAAO,QAAQ,KAAK,GAAG,CAAC,EAGxD,MAAMmB,EAAcD,EAAY,SAAA,EAC1B3C,EAAM,GAAG+B,EAAU,OAAO,qBAAqB,mBAAmBmB,CAAQ,CAAC,GAAGN,EAAc,IAAIA,CAAW,GAAK,EAAE,GACxH/E,EAAM,mBAAoBmC,CAAG,EAE7B,GAAI,CACF,MAAM4B,EAAW,MAAM,MAAM5B,EAAK,CAChC,OAAQ,MACR,QAAS,CACP,OAAU,mBACV,cAAiB,UAAU+B,EAAU,KAAK,EAAA,CAC5C,CACD,EAED,GAAI,CAACH,EAAS,GACZ,OAAOa,EAAoBb,CAAQ,EAGrC,MAAMtE,EAAO,MAAMsE,EAAS,KAAA,EAC5B,OAAA/D,EAAM,kBAAmBP,EAAK,IAAI,EAE3BD,EAAQC,CAAI,CACrB,OAAS2C,EAAK,CACZ,OAAO1C,EAAQ,gBAAiB,2BAA2B,OAAO0C,CAAG,CAAC,EAAE,CAC1E,CACF,CAMA,eAAewC,EAAuBb,EAAwC,CAC5E,MAAMlE,EAASkE,EAAS,OAExB,IAAInE,EACJ,GAAI,CACF,MAAMsF,EAAY,MAAMnB,EAAS,KAAA,EACjCnE,EAAUsF,EAAU,SAAWA,EAAU,OAASnB,EAAS,UAC7D,OAASuB,EAAY,CACnBtF,EAAM,uCAAwCsF,CAAU,EACxD1F,EAAUmE,EAAS,YAAc,eACnC,CAEA,OAAQlE,EAAA,CACN,IAAK,KACH,OAAOH,EAAQ,gBAAiB,0BAA0BE,CAAO,GAAIC,CAAM,EAC7E,IAAK,KACH,OAAOH,EAAQ,YAAa,kBAAkBE,CAAO,GAAIC,CAAM,EACjE,IAAK,KACH,OAAOH,EAAQ,YAAa,cAAcE,CAAO,GAAIC,CAAM,EAC7D,IAAK,KACH,OAAOH,EAAQ,eAAgB,iBAAiBE,CAAO,GAAIC,CAAM,EACnE,QACE,OAAOH,EAAQ,YAAa,cAAcE,CAAO,GAAIC,CAAM,CAAA,CAEjE"}
1
+ {"version":3,"file":"index.cjs","sources":["../src/config.ts","../src/types/common.ts","../src/utils/debug.ts","../src/auth/store.ts","../src/auth/service.ts","../src/users/service.ts","../src/cameras/service.ts","../src/bridges/service.ts"],"sourcesContent":["import type { EenToolkitConfig } from './types'\n\n/**\n * Global toolkit configuration\n */\nlet config: EenToolkitConfig = {}\n\n/**\n * Initialize the EEN API Toolkit\n */\nexport function initEenToolkit(options: EenToolkitConfig = {}): void {\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 debug: options.debug ?? import.meta.env?.VITE_DEBUG === 'true'\n }\n}\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 | '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 * 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 * 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 /** 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 * 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 { defineStore } from 'pinia'\nimport { ref, computed } from 'vue'\nimport type { UserProfile } from '../types'\nimport type { Result } from '../types'\nimport { debug } from '../utils/debug'\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\n function saveToStorage() {\n try {\n if (token.value) localStorage.setItem('een_token', token.value)\n if (tokenExpiration.value) localStorage.setItem('een_tokenExpiration', String(tokenExpiration.value))\n if (refreshTokenMarker.value) localStorage.setItem('een_refreshTokenMarker', refreshTokenMarker.value)\n if (sessionId.value) localStorage.setItem('een_sessionId', sessionId.value)\n if (hostname.value) localStorage.setItem('een_hostname', hostname.value)\n if (port.value !== 443) localStorage.setItem('een_port', String(port.value))\n if (userProfile.value) localStorage.setItem('een_userProfile', JSON.stringify(userProfile.value))\n } catch (err: unknown) {\n // localStorage might not be available (SSR, private browsing, etc.)\n debug('Failed to save to localStorage:', err instanceof Error ? err.message : String(err))\n }\n }\n\n function loadFromStorage() {\n try {\n token.value = localStorage.getItem('een_token')\n const expStr = localStorage.getItem('een_tokenExpiration')\n tokenExpiration.value = expStr ? parseInt(expStr, 10) : null\n refreshTokenMarker.value = localStorage.getItem('een_refreshTokenMarker')\n sessionId.value = localStorage.getItem('een_sessionId')\n hostname.value = localStorage.getItem('een_hostname')\n const portStr = localStorage.getItem('een_port')\n port.value = portStr ? parseInt(portStr, 10) : 443\n const profileStr = localStorage.getItem('een_userProfile')\n userProfile.value = profileStr ? JSON.parse(profileStr) : null\n } catch (err: unknown) {\n // localStorage might not be available (SSR, private browsing, etc.)\n debug('Failed to load from localStorage:', err instanceof Error ? err.message : String(err))\n }\n }\n\n function clearStorage() {\n try {\n localStorage.removeItem('een_token')\n localStorage.removeItem('een_tokenExpiration')\n localStorage.removeItem('een_refreshTokenMarker')\n localStorage.removeItem('een_sessionId')\n localStorage.removeItem('een_hostname')\n localStorage.removeItem('een_port')\n localStorage.removeItem('een_userProfile')\n } catch (err: unknown) {\n // localStorage might not be available (SSR, private browsing, etc.)\n debug('Failed to clear localStorage:', 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/listusers).\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"],"names":["config","initEenToolkit","options","__vite_import_meta_env__","getConfig","getProxyUrl","getClientId","getRedirectUri","success","data","failure","code","message","status","details","isDebugEnabled","debug","args","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","i","getCurrentUser","handleErrorResponse","getUsers","queryParams","queryString","getUser","userId","errorData","getCameras","getCamera","cameraId","parseError","getBridges","getBridge","bridgeId"],"mappings":"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"}