een-api-toolkit 0.0.18 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/CHANGELOG.md +52 -5
  2. package/README.md +29 -41
  3. package/dist/index.cjs +1 -1
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.d.ts +23 -821
  6. package/dist/index.js +234 -357
  7. package/dist/index.js.map +1 -1
  8. package/docs/AI-CONTEXT.md +38 -257
  9. package/examples/vue-cameras/e2e/app.spec.ts +2 -2
  10. package/examples/vue-cameras/e2e/auth.spec.ts +206 -0
  11. package/examples/vue-cameras/src/App.vue +4 -4
  12. package/examples/vue-cameras/src/views/CameraDetail.vue +57 -9
  13. package/examples/vue-cameras/src/views/Cameras.vue +69 -18
  14. package/examples/vue-cameras/src/views/Home.vue +36 -11
  15. package/examples/{vue-basic → vue-users}/README.md +4 -4
  16. package/examples/{vue-basic → vue-users}/e2e/app.spec.ts +3 -3
  17. package/examples/{vue-basic → vue-users}/e2e/auth.spec.ts +2 -2
  18. package/examples/{vue-basic → vue-users}/index.html +1 -1
  19. package/examples/{vue-basic → vue-users}/package-lock.json +3 -3
  20. package/examples/{vue-basic → vue-users}/package.json +1 -1
  21. package/examples/{vue-basic → vue-users}/src/App.vue +1 -1
  22. package/examples/{vue-basic → vue-users}/src/views/Home.vue +27 -12
  23. package/examples/{vue-basic → vue-users}/src/views/Users.vue +51 -10
  24. package/package.json +1 -1
  25. /package/examples/{vue-basic → vue-users}/.env.example +0 -0
  26. /package/examples/{vue-basic → vue-users}/playwright.config.ts +0 -0
  27. /package/examples/{vue-basic → vue-users}/src/main.ts +0 -0
  28. /package/examples/{vue-basic → vue-users}/src/router/index.ts +0 -0
  29. /package/examples/{vue-basic → vue-users}/src/views/Callback.vue +0 -0
  30. /package/examples/{vue-basic → vue-users}/src/views/Login.vue +0 -0
  31. /package/examples/{vue-basic → vue-users}/src/views/Logout.vue +0 -0
  32. /package/examples/{vue-basic → vue-users}/src/vite-env.d.ts +0 -0
  33. /package/examples/{vue-basic → vue-users}/tsconfig.json +0 -0
  34. /package/examples/{vue-basic → vue-users}/tsconfig.node.json +0 -0
  35. /package/examples/{vue-basic → vue-users}/vite.config.ts +0 -0
package/CHANGELOG.md CHANGED
@@ -2,20 +2,67 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
- ## [0.0.18] - 2025-12-30
5
+ ## [0.1.2] - 2025-12-30
6
6
 
7
7
  ### Release Summary
8
8
 
9
- No PR descriptions available for this release.
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
+
10
51
 
11
52
  ### Detailed Changes
12
53
 
13
54
  #### Other Changes
14
- - docs: Improve AI-CONTEXT.md with critical setup info at top
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
15
62
 
16
63
  ### Links
17
64
  - [npm package](https://www.npmjs.com/package/een-api-toolkit)
18
- - [Full Changelog](https://github.com/klaushofrichter/een-api-toolkit/compare/v0.0.17...v0.0.18)
65
+ - [Full Changelog](https://github.com/klaushofrichter/een-api-toolkit/compare/v0.0.18...v0.1.2)
19
66
 
20
67
  ---
21
- *Released: 2025-12-30 10:05:39 CST*
68
+ *Released: 2025-12-30 19:11:38 CST*
package/README.md CHANGED
@@ -4,7 +4,7 @@ A TypeScript library for the [Eagle Eye Networks](https://een.com/) Video API v3
4
4
 
5
5
  ## Purpose
6
6
 
7
- This toolkit aims to **simplify and accelerate web application development** for the EEN Video Platform. By providing ready-to-use composables, type-safe APIs, and secure authentication patterns, developers can focus on building features rather than wrestling with API integration details.
7
+ This toolkit aims to **simplify and accelerate web application development** for the EEN Video Platform. By providing type-safe APIs and secure authentication patterns, developers can focus on building features rather than wrestling with API integration details.
8
8
 
9
9
  The project is also designed to **enable AI-assisted software development**. With comprehensive documentation, clear code patterns, and an AI-optimized context file (`docs/AI-CONTEXT.md`), AI coding assistants can effectively help developers build, extend, and maintain applications using this toolkit.
10
10
 
@@ -12,11 +12,11 @@ The project is also designed to **enable AI-assisted software development**. Wit
12
12
 
13
13
  ## Key Features
14
14
 
15
- - **Vue 3 Composables** - Reactive state with `useCurrentUser()`, `useUsers()`, `useUser()`
16
- - **Plain Functions** - Framework-agnostic `getCurrentUser()`, `getUsers()`, `getUser()`
15
+ - **Plain Async Functions** - Simple API calls with `getCurrentUser()`, `getUsers()`, `getUser()`, `getCameras()`, `getCamera()`
17
16
  - **Secure OAuth** - Token management via proxy (refresh tokens never exposed to client)
18
17
  - **Type-Safe** - Full TypeScript types from OpenAPI spec
19
18
  - **Predictable Errors** - Always returns `{data, error}`, no exceptions thrown
19
+ - **Pinia Auth Store** - Reactive authentication state management
20
20
 
21
21
  ## OAuth Proxy Requirement
22
22
 
@@ -94,33 +94,8 @@ const onCallback = async (code: string, state: string) => {
94
94
 
95
95
  ### 5. Use the API
96
96
 
97
- **Vue Composables (reactive):**
98
-
99
- ```vue
100
- <script setup>
101
- import { useCurrentUser, useUsers } from 'een-api-toolkit'
102
-
103
- const { user, loading, error } = useCurrentUser()
104
- const { users, hasNextPage, fetchNextPage } = useUsers({ pageSize: 10 })
105
- </script>
106
-
107
- <template>
108
- <div v-if="loading">Loading...</div>
109
- <div v-else-if="error">{{ error.message }}</div>
110
- <div v-else>
111
- <h1>Welcome, {{ user.firstName }}</h1>
112
- <ul>
113
- <li v-for="u in users" :key="u.id">{{ u.email }}</li>
114
- </ul>
115
- <button v-if="hasNextPage" @click="fetchNextPage">Load More</button>
116
- </div>
117
- </template>
118
- ```
119
-
120
- **Plain Functions (framework-agnostic):**
121
-
122
97
  ```typescript
123
- import { getUsers, getCurrentUser } from 'een-api-toolkit'
98
+ import { getUsers, getCurrentUser, getCameras } from 'een-api-toolkit'
124
99
 
125
100
  // Get current authenticated user
126
101
  const { data: currentUser, error: userError } = await getCurrentUser()
@@ -130,12 +105,25 @@ if (userError) {
130
105
  console.log('Current user:', currentUser.email)
131
106
  }
132
107
 
133
- // Get list of users
134
- const { data: users, error } = await getUsers()
108
+ // Get list of users with pagination
109
+ const { data: usersData, error } = await getUsers({ pageSize: 10 })
135
110
  if (error) {
136
111
  console.error(error.code, error.message)
137
112
  } else {
138
- console.log('Users:', users.results)
113
+ console.log('Users:', usersData.results)
114
+ if (usersData.nextPageToken) {
115
+ // Fetch next page
116
+ const { data: nextPage } = await getUsers({ pageToken: usersData.nextPageToken })
117
+ }
118
+ }
119
+
120
+ // Get list of cameras
121
+ const { data: camerasData, error: cameraError } = await getCameras({
122
+ pageSize: 20,
123
+ include: ['deviceInfo', 'status']
124
+ })
125
+ if (!cameraError) {
126
+ console.log('Cameras:', camerasData.results)
139
127
  }
140
128
  ```
141
129
 
@@ -146,16 +134,16 @@ if (error) {
146
134
  │ Your Vue 3 App │
147
135
  │ ┌────────────────────────────────────────────────────────────────┐ │
148
136
  │ │ import from 'een-api-toolkit' │ │
149
- │ │ ┌──────────────┐ ┌────────────────────┐ │ │
150
- │ │ Composables │ │ Plain Functions │ │
151
- │ │ useUsers() │ │ getUsers() │ │
152
- │ │ useUser() │ │ getUser() │ │ │
153
- │ │ └──────────────┘ └────────────────────┘ │ │
137
+ │ │ ┌────────────────────────────────────┐ │ │
138
+ │ │ Plain Async Functions │ │
139
+ │ │ getUsers(), getCameras() │ │
140
+ │ │ getUser(), getCamera() │ │ │
141
+ │ │ └────────────────────────────────────┘ │ │
154
142
  │ └────────────────────────────────────────────────────────────────┘ │
155
-
156
-
143
+
144
+
157
145
  │ ┌─────────────────────┐ ┌─────────────────────┐ │
158
- │ │ Pinia Auth Store │ │ API Calls with │ │
146
+ │ │ Pinia Auth Store │◄──────►│ API Calls with │ │
159
147
  │ │ (token, baseUrl) │ │ Bearer Token │ │
160
148
  │ └─────────────────────┘ └─────────────────────┘ │
161
149
  └────────────────────│─────────────────────────────│───────────────────┘
@@ -181,7 +169,7 @@ if (error) {
181
169
  | **[User Guide](./docs/USER-GUIDE.md)** | Installation, proxy setup, configuration, building apps |
182
170
  | **[Developer Guide](./docs/DEVELOPER-GUIDE.md)** | Architecture, testing, CI/CD, contributing |
183
171
  | **[API Reference](./docs/api/)** | Auto-generated TypeDoc documentation |
184
- | **[Example App](./examples/vue-basic/)** | Complete Vue 3 example with OAuth flow |
172
+ | **[Example App](./examples/vue-users/)** | Complete Vue 3 example with OAuth flow |
185
173
  | **[AI Context](./docs/AI-CONTEXT.md)** | Single-file reference for AI assistants (also in npm package) |
186
174
  | **[AI Prompts](./docs/Prompts.md)** | Example prompts for generating apps with AI |
187
175
 
package/dist/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const ie=require("pinia"),s=require("vue"),E={};let D={};function se(e={}){D={proxyUrl:e.proxyUrl??E?.VITE_PROXY_URL,clientId:e.clientId??E?.VITE_EEN_CLIENT_ID,redirectUri:e.redirectUri??E?.VITE_REDIRECT_URI,debug:e.debug??E?.VITE_DEBUG==="true"}}function ue(){return D}function x(){return D.proxyUrl??E?.VITE_PROXY_URL}function b(){return D.clientId??E?.VITE_EEN_CLIENT_ID}function C(){return D.redirectUri??E?.VITE_REDIRECT_URI??"http://127.0.0.1:3333"}function p(e){return{data:e,error:null}}function u(e,n,t,r){return{data:null,error:{code:e,message:n,status:t,details:r}}}const le={BASE_URL:"/",DEV:!1,MODE:"production",PROD:!0,SSR:!1},ce=()=>{try{return le?.VITE_DEBUG==="true"}catch{return!1}};function c(...e){ce()&&console.log("[een-api-toolkit]",...e)}let w=null;function fe(){return w||(w=Promise.resolve().then(()=>ge).then(e=>e.refreshToken)),w}const R=ie.defineStore("een-auth",()=>{const e=s.ref(null),n=s.ref(null),t=s.ref(null),r=s.ref(null),o=s.ref(null),a=s.ref(443),i=s.ref(null),d=s.ref(null),I=s.ref(!1);let h=null;const _=s.ref(!1),f=s.ref(null),S=s.computed(()=>!!e.value),k=s.computed(()=>o.value?a.value===443?`https://${o.value}`:`https://${o.value}:${a.value}`:null),U=s.computed(()=>n.value?Date.now()>=n.value:!0),m=s.computed(()=>n.value?Math.max(0,n.value-Date.now()):0);function T(l,g){e.value=l,n.value=Date.now()+g*1e3,y(),$(),c("Token set, expires in",g,"seconds")}function A(l){t.value=l,y()}function v(l){r.value=l,y()}function K(l){if(typeof l=="string")try{const g=new URL(l.startsWith("http")?l:`https://${l}`);o.value=g.hostname,a.value=g.port?parseInt(g.port,10):443}catch(g){c("Failed to parse URL, using as hostname:",g instanceof Error?g.message:String(g)),o.value=l,a.value=443}else o.value=l.hostname,a.value=l.port??443;y(),c("Base URL set:",k.value)}function J(l){i.value=l,y()}function $(){if(d.value&&(clearTimeout(d.value),d.value=null),!n.value||!e.value)return;const l=Date.now(),P=n.value-l,ne=300*1e3,re=P/2,oe=Math.min(ne,re),ae=Math.max(P-oe,60*1e3),F=Math.max(ae,5e3);c("Auto-refresh scheduled in",Math.round(F/1e3),"seconds"),d.value=setTimeout(async()=>{await X()},F)}async function X(){return h?(c("Refresh already in progress, waiting for existing refresh"),h):(I.value=!0,c("Performing auto-refresh"),h=(async()=>{try{const g=await(await fe())();g.error?(_.value=!0,f.value=g.error.message,c("Auto-refresh failed:",g.error.message)):(_.value=!1,f.value=null,c("Auto-refresh successful"))}catch(l){_.value=!0,f.value=l instanceof Error?l.message:String(l),c("Auto-refresh error:",l)}finally{I.value=!1,h=null}})(),h)}function Y(){_.value=!1,f.value=null}function j(){d.value&&(clearTimeout(d.value),d.value=null),e.value=null,n.value=null,t.value=null,r.value=null,o.value=null,a.value=443,i.value=null,_.value=!1,f.value=null,te(),c("Logged out")}function Z(){ee(),e.value&&!U.value?($(),c("Initialized from storage")):e.value&&U.value&&(c("Stored token expired, clearing"),j())}function y(){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),o.value&&localStorage.setItem("een_hostname",o.value),a.value!==443&&localStorage.setItem("een_port",String(a.value)),i.value&&localStorage.setItem("een_userProfile",JSON.stringify(i.value))}catch(l){c("Failed to save to localStorage:",l instanceof Error?l.message:String(l))}}function ee(){try{e.value=localStorage.getItem("een_token");const l=localStorage.getItem("een_tokenExpiration");n.value=l?parseInt(l,10):null,t.value=localStorage.getItem("een_refreshTokenMarker"),r.value=localStorage.getItem("een_sessionId"),o.value=localStorage.getItem("een_hostname");const g=localStorage.getItem("een_port");a.value=g?parseInt(g,10):443;const P=localStorage.getItem("een_userProfile");i.value=P?JSON.parse(P):null}catch(l){c("Failed to load from localStorage:",l instanceof Error?l.message:String(l))}}function te(){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(l){c("Failed to clear localStorage:",l instanceof Error?l.message:String(l))}}return{token:e,tokenExpiration:n,refreshTokenMarker:t,sessionId:r,hostname:o,port:a,userProfile:i,isRefreshing:I,refreshFailed:_,refreshFailedMessage:f,isAuthenticated:S,baseUrl:k,isTokenExpired:U,tokenExpiresIn:m,setToken:T,setRefreshTokenMarker:A,setSessionId:v,setBaseUrl:K,setUserProfile:J,setupAutoRefresh:$,clearRefreshFailed:Y,logout:j,initialize:Z}}),de="https://auth.eagleeyenetworks.com/oauth2/authorize";function N(){const e=b();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:C(),state:n});return c("Generated auth URL with state:",n),`${de}?${t.toString()}`}async function O(e){const n=x();if(!n)return u("AUTH_FAILED","Proxy URL not configured. Call initEenToolkit() or set VITE_PROXY_URL");const t=new URLSearchParams({code:e,redirect_uri:C()});try{const r=await fetch(`${n}/proxy/getAccessToken?${t.toString()}`,{method:"POST",credentials:"include",headers:{Accept:"application/json"}});if(!r.ok){const a=await r.text().catch(()=>"Unknown error");return u("AUTH_FAILED",`Token exchange failed: ${a}`,r.status)}const o=await r.json();return c("Token received, expires in:",o.expiresIn),p(o)}catch(r){return u("NETWORK_ERROR",`Failed to exchange code: ${String(r)}`)}}async function q(){const e=x();if(!e)return u("AUTH_FAILED","Proxy URL not configured");const n=R();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 a=await r.text().catch(()=>"Unknown error");return u("AUTH_FAILED",`Token refresh failed: ${a}`,r.status)}const o=await r.json();return n.setToken(o.accessToken,o.expiresIn),c("Token refreshed, expires in:",o.expiresIn),p(o)}catch(t){return u("NETWORK_ERROR",`Failed to refresh token: ${String(t)}`)}}async function M(){const e=x();if(!e)return u("AUTH_FAILED","Proxy URL not configured");const n=R();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 o=await r.text().catch(()=>"Unknown error");return u("AUTH_FAILED",`Token revocation failed: ${o}`,r.status)}return c("Token revoked"),p(void 0)}catch(t){return n.logout(),u("NETWORK_ERROR",`Failed to revoke token: ${String(t)}`)}}async function B(e,n){let t=null;try{t=sessionStorage.getItem("een_oauth_state"),sessionStorage.removeItem("een_oauth_state")}catch{}if(!t)return u("AUTH_FAILED","No OAuth state found. Please restart the login process.");if(!_e(n,t))return u("AUTH_FAILED","Invalid OAuth state. Possible CSRF attack.");c("State validated, exchanging code for token");const r=await O(e);if(r.error)return r;const o=R(),a=r.data;return o.setToken(a.accessToken,a.expiresIn),o.setRefreshTokenMarker("present"),o.setSessionId(a.sessionId),o.setBaseUrl(a.httpsBaseUrl),c("Auth callback complete, user:",a.userEmail),p(a)}function _e(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 ge=Object.freeze(Object.defineProperty({__proto__:null,getAccessToken:O,getAuthUrl:N,handleAuthCallback:B,refreshToken:q,revokeToken:M},Symbol.toStringTag,{value:"Module"}));async function z(){const e=R();if(!e.isAuthenticated)return u("AUTH_REQUIRED","Authentication required");if(!e.baseUrl)return u("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 L(t);const r=await t.json();return c("Current user fetched:",r.email),e.setUserProfile(r),p(r)}catch(t){return u("NETWORK_ERROR",`Failed to fetch current user: ${String(t)}`)}}async function H(e){const n=R();if(!n.isAuthenticated)return u("AUTH_REQUIRED","Authentication required");if(!n.baseUrl)return u("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(),o=`${n.baseUrl}/api/v3.0/users${r?`?${r}`:""}`;c("Fetching users:",o);try{const a=await fetch(o,{method:"GET",headers:{Accept:"application/json",Authorization:`Bearer ${n.token}`}});if(!a.ok)return L(a);const i=await a.json();return c("Users fetched:",i.results?.length??0,"users"),p(i)}catch(a){return u("NETWORK_ERROR",`Failed to fetch users: ${String(a)}`)}}async function V(e,n){const t=R();if(!t.isAuthenticated)return u("AUTH_REQUIRED","Authentication required");if(!t.baseUrl)return u("AUTH_REQUIRED","Base URL not configured");if(!e)return u("VALIDATION_ERROR","User ID is required");const r=new URLSearchParams;n?.include&&n.include.length>0&&r.append("include",n.include.join(","));const o=r.toString(),a=`${t.baseUrl}/api/v3.0/users/${encodeURIComponent(e)}${o?`?${o}`:""}`;c("Fetching user:",a);try{const i=await fetch(a,{method:"GET",headers:{Accept:"application/json",Authorization:`Bearer ${t.token}`}});if(!i.ok)return L(i);const d=await i.json();return c("User fetched:",d.email),p(d)}catch(i){return u("NETWORK_ERROR",`Failed to fetch user: ${String(i)}`)}}async function L(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 u("AUTH_REQUIRED",`Authentication failed: ${t}`,n);case 403:return u("FORBIDDEN",`Access denied: ${t}`,n);case 404:return u("NOT_FOUND",`Not found: ${t}`,n);case 429:return u("RATE_LIMITED",`Rate limited: ${t}`,n);default:return u("API_ERROR",`API error: ${t}`,n)}}function he(e){const n=s.ref(null),t=s.ref(!1),r=s.ref(null),o=async()=>{t.value=!0,r.value=null;const i=await z();return i.error?(r.value=i.error,n.value=null):n.value=i.data,t.value=!1,i},a=o;return e?.immediate!==!1&&s.onMounted(o),{user:n,loading:t,error:r,fetch:o,refresh:a}}function ve(e,n){const t=s.ref([]),r=s.ref(!1),o=s.ref(null),a=s.ref(void 0),i=s.ref(void 0),d=s.ref(void 0),I=s.computed(()=>!!a.value),h=s.computed(()=>!!i.value),_=s.ref(e??{}),f=async T=>{r.value=!0,o.value=null;const A={..._.value,...T},v=await H(A);return v.error?(o.value=v.error,t.value=[],a.value=void 0,i.value=void 0,d.value=void 0):(t.value=v.data.results,a.value=v.data.nextPageToken,i.value=v.data.prevPageToken,d.value=v.data.totalSize),r.value=!1,v},S=()=>f(),k=async()=>{if(a.value)return f({..._.value,pageToken:a.value})},U=async()=>{if(i.value)return f({..._.value,pageToken:i.value})},m=T=>{_.value=T};return n?.immediate!==!1&&s.onMounted(f),{users:t,loading:r,error:o,nextPageToken:a,prevPageToken:i,totalSize:d,hasNextPage:I,hasPrevPage:h,params:_,fetch:f,refresh:S,fetchNextPage:k,fetchPrevPage:U,setParams:m}}function Ie(e,n){const t=s.ref(null),r=s.ref(!1),o=s.ref(null),a=()=>typeof e=="function"?e():e,i=async I=>{const h=a();if(!h)return o.value={code:"VALIDATION_ERROR",message:"User ID is required"},{data:null,error:o.value};r.value=!0,o.value=null;const _={include:n?.include,...I},f=await V(h,_);return f.error?(o.value=f.error,t.value=null):t.value=f.data,r.value=!1,f},d=()=>i();return n?.immediate!==!1&&a()&&s.onMounted(i),{user:t,loading:r,error:o,fetch:i,refresh:d}}async function Q(e){const n=R();if(!n.isAuthenticated)return u("AUTH_REQUIRED","Authentication required");if(!n.baseUrl)return u("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(),o=`${n.baseUrl}/api/v3.0/cameras${r?`?${r}`:""}`;c("Fetching cameras:",o);try{const a=await fetch(o,{method:"GET",headers:{Accept:"application/json",Authorization:`Bearer ${n.token}`}});if(!a.ok)return G(a);const i=await a.json();return c("Cameras fetched:",i.results?.length??0,"cameras"),p(i)}catch(a){return u("NETWORK_ERROR",`Failed to fetch cameras: ${String(a)}`)}}async function W(e,n){const t=R();if(!t.isAuthenticated)return u("AUTH_REQUIRED","Authentication required");if(!t.baseUrl)return u("AUTH_REQUIRED","Base URL not configured");if(!e)return u("VALIDATION_ERROR","Camera ID is required");const r=new URLSearchParams;n?.include&&n.include.length>0&&r.append("include",n.include.join(","));const o=r.toString(),a=`${t.baseUrl}/api/v3.0/cameras/${encodeURIComponent(e)}${o?`?${o}`:""}`;c("Fetching camera:",a);try{const i=await fetch(a,{method:"GET",headers:{Accept:"application/json",Authorization:`Bearer ${t.token}`}});if(!i.ok)return G(i);const d=await i.json();return c("Camera fetched:",d.name),p(d)}catch(i){return u("NETWORK_ERROR",`Failed to fetch camera: ${String(i)}`)}}async function G(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 u("AUTH_REQUIRED",`Authentication failed: ${t}`,n);case 403:return u("FORBIDDEN",`Access denied: ${t}`,n);case 404:return u("NOT_FOUND",`Not found: ${t}`,n);case 429:return u("RATE_LIMITED",`Rate limited: ${t}`,n);default:return u("API_ERROR",`API error: ${t}`,n)}}function pe(e,n){const t=s.ref([]),r=s.ref(!1),o=s.ref(null),a=s.ref(void 0),i=s.ref(void 0),d=s.ref(void 0),I=s.computed(()=>!!a.value),h=s.computed(()=>!!i.value),_=s.ref(e??{}),f=async T=>{r.value=!0,o.value=null;const A={..._.value,...T},v=await Q(A);return v.error?(o.value=v.error,t.value=[],a.value=void 0,i.value=void 0,d.value=void 0):(t.value=v.data.results,a.value=v.data.nextPageToken,i.value=v.data.prevPageToken,d.value=v.data.totalSize),r.value=!1,v},S=()=>f(),k=async()=>{if(a.value)return f({..._.value,pageToken:a.value})},U=async()=>{if(i.value)return f({..._.value,pageToken:i.value})},m=T=>{_.value=T};return n?.immediate!==!1&&s.onMounted(f),{cameras:t,loading:r,error:o,nextPageToken:a,prevPageToken:i,totalSize:d,hasNextPage:I,hasPrevPage:h,params:_,fetch:f,refresh:S,fetchNextPage:k,fetchPrevPage:U,setParams:m}}function Te(e,n){const t=s.ref(null),r=s.ref(!1),o=s.ref(null),a=()=>typeof e=="function"?e():e,i=async I=>{const h=a();if(!h)return o.value={code:"VALIDATION_ERROR",message:"Camera ID is required"},{data:null,error:o.value};r.value=!0,o.value=null;const _={include:n?.include,...I},f=await W(h,_);return f.error?(o.value=f.error,t.value=null):t.value=f.data,r.value=!1,f},d=()=>i();return n?.immediate!==!1&&a()&&s.onMounted(i),typeof e=="function"&&s.watch(e,(I,h)=>{I&&I!==h&&i()}),{camera:t,loading:r,error:o,fetch:i,refresh:d}}exports.failure=u;exports.getAccessToken=O;exports.getAuthUrl=N;exports.getCamera=W;exports.getCameras=Q;exports.getClientId=b;exports.getConfig=ue;exports.getCurrentUser=z;exports.getProxyUrl=x;exports.getRedirectUri=C;exports.getUser=V;exports.getUsers=H;exports.handleAuthCallback=B;exports.initEenToolkit=se;exports.refreshToken=q;exports.revokeToken=M;exports.success=p;exports.useAuthStore=R;exports.useCamera=Te;exports.useCameras=pe;exports.useCurrentUser=he;exports.useUser=Ie;exports.useUsers=ve;
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;
2
2
  //# sourceMappingURL=index.cjs.map