een-api-toolkit 0.1.4 → 0.1.10
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 +78 -6
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +607 -1
- package/dist/index.js +473 -264
- package/dist/index.js.map +1 -1
- package/docs/AI-CONTEXT.md +160 -1
- package/examples/vue-feeds/.env.example +4 -0
- package/examples/vue-feeds/e2e/app.spec.ts +55 -0
- package/examples/vue-feeds/e2e/auth.spec.ts +417 -0
- package/examples/vue-feeds/index.html +13 -0
- package/examples/vue-feeds/package-lock.json +1583 -0
- package/examples/vue-feeds/package.json +28 -0
- package/examples/vue-feeds/playwright.config.ts +28 -0
- package/examples/vue-feeds/src/App.vue +128 -0
- package/examples/vue-feeds/src/main.ts +22 -0
- package/examples/vue-feeds/src/router/index.ts +61 -0
- package/examples/vue-feeds/src/views/Callback.vue +76 -0
- package/examples/vue-feeds/src/views/Feeds.vue +368 -0
- package/examples/vue-feeds/src/views/Home.vue +95 -0
- package/examples/vue-feeds/src/views/Login.vue +32 -0
- package/examples/vue-feeds/src/views/Logout.vue +59 -0
- package/examples/vue-feeds/src/vite-env.d.ts +12 -0
- package/examples/vue-feeds/tsconfig.json +21 -0
- package/examples/vue-feeds/tsconfig.node.json +11 -0
- package/examples/vue-feeds/vite.config.ts +12 -0
- package/examples/vue-media/.env.example +5 -0
- package/examples/vue-media/e2e/app.spec.ts +63 -0
- package/examples/vue-media/e2e/auth.spec.ts +574 -0
- package/examples/vue-media/index.html +13 -0
- package/examples/vue-media/package-lock.json +1583 -0
- package/examples/vue-media/package.json +28 -0
- package/examples/vue-media/playwright.config.ts +28 -0
- package/examples/vue-media/src/App.vue +129 -0
- package/examples/vue-media/src/composables/useSelectedCamera.ts +95 -0
- package/examples/vue-media/src/main.ts +22 -0
- package/examples/vue-media/src/router/index.ts +68 -0
- package/examples/vue-media/src/views/Callback.vue +76 -0
- package/examples/vue-media/src/views/Home.vue +99 -0
- package/examples/vue-media/src/views/LiveCamera.vue +338 -0
- package/examples/vue-media/src/views/Login.vue +32 -0
- package/examples/vue-media/src/views/Logout.vue +59 -0
- package/examples/vue-media/src/views/RecordedImage.vue +448 -0
- package/examples/vue-media/src/vite-env.d.ts +12 -0
- package/examples/vue-media/tsconfig.json +21 -0
- package/examples/vue-media/tsconfig.node.json +10 -0
- package/examples/vue-media/vite.config.ts +12 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,23 +2,95 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
-
## [0.1.
|
|
5
|
+
## [0.1.10] - 2025-12-31
|
|
6
6
|
|
|
7
7
|
### Release Summary
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
#### PR #35: feat: Add RecordedImage page with shared camera selection
|
|
10
|
+
## Summary
|
|
11
|
+
|
|
12
|
+
Adds a new RecordedImage page to the vue-media example app with shared camera selection between Live and Recorded pages.
|
|
13
|
+
|
|
14
|
+
### Changes
|
|
15
|
+
- **RecordedImage.vue**: New page with date/time picker, prev/next navigation for browsing recorded images
|
|
16
|
+
- **useSelectedCamera composable**: Shared camera state persisted via localStorage across pages
|
|
17
|
+
- **LiveCamera.vue**: Added "View Recorded Images" button, uses shared camera composable
|
|
18
|
+
- **Navigation**: Updated App.vue nav and Home.vue with links to Recorded page
|
|
19
|
+
- **Router**: Added /recorded route
|
|
20
|
+
- **E2E Tests**: Comprehensive tests for recorded image functionality and camera persistence
|
|
21
|
+
|
|
22
|
+
### Commits
|
|
23
|
+
- 61e4e88 feat: Add RecordedImage page with shared camera selection
|
|
24
|
+
|
|
25
|
+
## Test Results
|
|
26
|
+
- Lint: ✅ Passed (1 warning)
|
|
27
|
+
- Unit tests: ✅ 131 passed
|
|
28
|
+
- Build: ✅ Passed
|
|
29
|
+
|
|
30
|
+
## Version
|
|
31
|
+
`0.1.7`
|
|
32
|
+
|
|
33
|
+
🤖 Generated with [Claude Code](https://claude.com/claude-code)
|
|
34
|
+
|
|
35
|
+
#### PR #36: feat: RecordedImage page, code review fixes, and timestamp documentation
|
|
36
|
+
## Summary
|
|
37
|
+
|
|
38
|
+
This PR adds the RecordedImage page to the vue-media example, addresses code review feedback, and documents the critical EEN timestamp format requirement.
|
|
39
|
+
|
|
40
|
+
### Features
|
|
41
|
+
- **RecordedImage.vue**: New page with date/time picker, prev/next navigation for browsing recorded images
|
|
42
|
+
- **Shared camera selection**: Camera selection persists between Live and Recorded pages via localStorage
|
|
43
|
+
- **Time picker sync**: Automatically updates to show current image timestamp
|
|
44
|
+
|
|
45
|
+
### Security & Robustness Fixes
|
|
46
|
+
- Camera ID validation with regex pattern to prevent XSS via localStorage
|
|
47
|
+
- localStorage operations wrapped in try-catch for private browsing support
|
|
48
|
+
- Initialization flag to prevent race conditions in composable
|
|
49
|
+
- Extracted `_fetchImage` helper to eliminate duplication
|
|
50
|
+
- Fixed stale data bug - image data cleared on error
|
|
51
|
+
- Added ARIA labels for accessibility
|
|
52
|
+
|
|
53
|
+
### Documentation
|
|
54
|
+
- Added Media API section to USER-GUIDE.md
|
|
55
|
+
- Documented EEN timestamp format requirement (ISO 8601 with timezone offset, not Z suffix)
|
|
56
|
+
- Added `toApiTimestamp()` helper function example
|
|
57
|
+
- Updated AI-CONTEXT.md with same documentation
|
|
58
|
+
|
|
59
|
+
### Commits
|
|
60
|
+
- 52f411b docs: Add EEN timestamp format documentation for recorded images
|
|
61
|
+
- c635af2 Merge pull request #35 from klaushofrichter/develop
|
|
62
|
+
- 6179fda fix: Address code review feedback for RecordedImage page
|
|
63
|
+
- 61e4e88 feat: Add RecordedImage page with shared camera selection
|
|
64
|
+
|
|
65
|
+
## Test Results
|
|
66
|
+
- Lint: ✅ Passed (1 warning)
|
|
67
|
+
- Unit tests: ✅ 131 passed
|
|
68
|
+
- Build: ✅ Passed
|
|
69
|
+
|
|
70
|
+
## Version
|
|
71
|
+
`0.1.7`
|
|
72
|
+
|
|
73
|
+
🤖 Generated with [Claude Code](https://claude.com/claude-code)
|
|
74
|
+
|
|
10
75
|
|
|
11
76
|
### Detailed Changes
|
|
12
77
|
|
|
13
78
|
#### Features
|
|
14
|
-
- feat: Add
|
|
79
|
+
- feat: Add Feeds API with listFeeds function and vue-feeds example
|
|
80
|
+
- feat: Add RecordedImage page with shared camera selection
|
|
15
81
|
|
|
16
82
|
#### Bug Fixes
|
|
17
|
-
- fix: Address code review
|
|
83
|
+
- fix: Address additional code review concerns
|
|
84
|
+
- fix: Address code review feedback from PR #37
|
|
85
|
+
- fix: Address code review feedback for RecordedImage page
|
|
86
|
+
|
|
87
|
+
#### Other Changes
|
|
88
|
+
- docs: Fix timestamp examples and regenerate AI-CONTEXT
|
|
89
|
+
- docs: Add EEN timestamp format documentation for recorded images
|
|
18
90
|
|
|
19
91
|
### Links
|
|
20
92
|
- [npm package](https://www.npmjs.com/package/een-api-toolkit)
|
|
21
|
-
- [Full Changelog](https://github.com/klaushofrichter/een-api-toolkit/compare/v0.1.
|
|
93
|
+
- [Full Changelog](https://github.com/klaushofrichter/een-api-toolkit/compare/v0.1.7...v0.1.10)
|
|
22
94
|
|
|
23
95
|
---
|
|
24
|
-
*Released: 2025-12-31
|
|
96
|
+
*Released: 2025-12-31 20:55:04 CST*
|
package/dist/index.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
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;
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const oe=require("pinia"),f=require("vue"),T={};let v={};function ae(e={}){v={proxyUrl:e.proxyUrl??T?.VITE_PROXY_URL,clientId:e.clientId??T?.VITE_EEN_CLIENT_ID,redirectUri:e.redirectUri??T?.VITE_REDIRECT_URI,debug:e.debug??T?.VITE_DEBUG==="true"}}function se(){return v}function y(){return v.proxyUrl??T?.VITE_PROXY_URL}function F(){return v.clientId??T?.VITE_EEN_CLIENT_ID}function $(){return v.redirectUri??T?.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 ce={BASE_URL:"/",DEV:!1,MODE:"production",PROD:!0,SSR:!1},ue=()=>{try{return ce?.VITE_DEBUG==="true"}catch{return!1}};function c(...e){ue()&&console.log("[een-api-toolkit]",...e)}let D=null;function le(){return D||(D=Promise.resolve().then(()=>fe).then(e=>e.refreshToken)),D}const g=oe.defineStore("een-auth",()=>{const e=f.ref(null),n=f.ref(null),t=f.ref(null),r=f.ref(null),s=f.ref(null),o=f.ref(443),a=f.ref(null),l=f.ref(null),p=f.ref(!1);let R=null;const h=f.ref(!1),I=f.ref(null),U=f.computed(()=>!!e.value),S=f.computed(()=>s.value?o.value===443?`https://${s.value}`:`https://${s.value}:${o.value}`:null),k=f.computed(()=>n.value?Date.now()>=n.value:!0),M=f.computed(()=>n.value?Math.max(0,n.value-Date.now()):0);function Q(u,d){e.value=u,n.value=Date.now()+d*1e3,E(),m(),c("Token set, expires in",d,"seconds")}function V(u){t.value=u,E()}function W(u){r.value=u,E()}function K(u){if(typeof u=="string")try{const d=new URL(u.startsWith("http")?u:`https://${u}`);s.value=d.hostname,o.value=d.port?parseInt(d.port,10):443}catch(d){c("Failed to parse URL, using as hostname:",d instanceof Error?d.message:String(d)),s.value=u,o.value=443}else s.value=u.hostname,o.value=u.port??443;E(),c("Base URL set:",S.value)}function G(u){a.value=u,E()}function m(){if(l.value&&(clearTimeout(l.value),l.value=null),!n.value||!e.value)return;const u=Date.now(),A=n.value-u,te=300*1e3,ne=A/2,re=Math.min(te,ne),ie=Math.max(A-re,60*1e3),N=Math.max(ie,5e3);c("Auto-refresh scheduled in",Math.round(N/1e3),"seconds"),l.value=setTimeout(async()=>{await X()},N)}async function X(){return R?(c("Refresh already in progress, waiting for existing refresh"),R):(p.value=!0,c("Performing auto-refresh"),R=(async()=>{try{const d=await(await le())();d.error?(h.value=!0,I.value=d.error.message,c("Auto-refresh failed:",d.error.message)):(h.value=!1,I.value=null,c("Auto-refresh successful"))}catch(u){h.value=!0,I.value=u instanceof Error?u.message:String(u),c("Auto-refresh error:",u)}finally{p.value=!1,R=null}})(),R)}function J(){h.value=!1,I.value=null}function j(){l.value&&(clearTimeout(l.value),l.value=null),e.value=null,n.value=null,t.value=null,r.value=null,s.value=null,o.value=443,a.value=null,h.value=!1,I.value=null,ee(),c("Logged out")}function Y(){Z(),e.value&&!k.value?(m(),c("Initialized from storage")):e.value&&k.value&&(c("Stored token expired, clearing"),j())}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),s.value&&localStorage.setItem("een_hostname",s.value),o.value!==443&&localStorage.setItem("een_port",String(o.value)),a.value&&localStorage.setItem("een_userProfile",JSON.stringify(a.value))}catch(u){c("Failed to save to localStorage:",u instanceof Error?u.message:String(u))}}function Z(){try{e.value=localStorage.getItem("een_token");const u=localStorage.getItem("een_tokenExpiration");n.value=u?parseInt(u,10):null,t.value=localStorage.getItem("een_refreshTokenMarker"),r.value=localStorage.getItem("een_sessionId"),s.value=localStorage.getItem("een_hostname");const d=localStorage.getItem("een_port");o.value=d?parseInt(d,10):443;const A=localStorage.getItem("een_userProfile");a.value=A?JSON.parse(A):null}catch(u){c("Failed to load from localStorage:",u instanceof Error?u.message:String(u))}}function ee(){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(u){c("Failed to clear localStorage:",u instanceof Error?u.message:String(u))}}return{token:e,tokenExpiration:n,refreshTokenMarker:t,sessionId:r,hostname:s,port:o,userProfile:a,isRefreshing:p,refreshFailed:h,refreshFailedMessage:I,isAuthenticated:U,baseUrl:S,isTokenExpired:k,tokenExpiresIn:M,setToken:Q,setRefreshTokenMarker:V,setSessionId:W,setBaseUrl:K,setUserProfile:G,setupAutoRefresh:m,clearRefreshFailed:J,logout:j,initialize:Y}}),de="https://auth.eagleeyenetworks.com/oauth2/authorize";function P(){const e=F();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),`${de}?${t.toString()}`}async function O(e){const n=y();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:$()});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 s=await r.json();return c("Token received, expires in:",s.expiresIn),_(s)}catch(r){return i("NETWORK_ERROR",`Failed to exchange code: ${String(r)}`)}}async function q(){const e=y();if(!e)return i("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 o=await r.text().catch(()=>"Unknown error");return i("AUTH_FAILED",`Token refresh failed: ${o}`,r.status)}const s=await r.json();return n.setToken(s.accessToken,s.expiresIn),c("Token refreshed, expires in:",s.expiresIn),_(s)}catch(t){return i("NETWORK_ERROR",`Failed to refresh token: ${String(t)}`)}}async function x(){const e=y();if(!e)return i("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 s=await r.text().catch(()=>"Unknown error");return i("AUTH_FAILED",`Token revocation failed: ${s}`,r.status)}return c("Token revoked"),_(void 0)}catch(t){return n.logout(),i("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 i("AUTH_FAILED","No OAuth state found. Please restart the login process.");if(!_e(n,t))return i("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 s=g(),o=r.data;return s.setToken(o.accessToken,o.expiresIn),s.setRefreshTokenMarker("present"),s.setSessionId(o.sessionId),s.setBaseUrl(o.httpsBaseUrl),c("Auth callback complete, user:",o.userEmail),_(o)}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 fe=Object.freeze(Object.defineProperty({__proto__:null,getAccessToken:O,getAuthUrl:P,handleAuthCallback:B,refreshToken:q,revokeToken:x},Symbol.toStringTag,{value:"Module"}));async function ge(){const e=g();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 b(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 he(e){const n=g();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(),s=`${n.baseUrl}/api/v3.0/users${r?`?${r}`:""}`;c("Fetching users:",s);try{const o=await fetch(s,{method:"GET",headers:{Accept:"application/json",Authorization:`Bearer ${n.token}`}});if(!o.ok)return b(o);const a=await o.json();return c("Users fetched:",a.results?.length??0,"users"),_(a)}catch(o){return i("NETWORK_ERROR",`Failed to fetch users: ${String(o)}`)}}async function Re(e,n){const t=g();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 s=r.toString(),o=`${t.baseUrl}/api/v3.0/users/${encodeURIComponent(e)}${s?`?${s}`:""}`;c("Fetching user:",o);try{const a=await fetch(o,{method:"GET",headers:{Accept:"application/json",Authorization:`Bearer ${t.token}`}});if(!a.ok)return b(a);const l=await a.json();return c("User fetched:",l.email),_(l)}catch(a){return i("NETWORK_ERROR",`Failed to fetch user: ${String(a)}`)}}async function b(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 Ie(e){const n=g();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(),s=`${n.baseUrl}/api/v3.0/cameras${r?`?${r}`:""}`;c("Fetching cameras:",s);try{const o=await fetch(s,{method:"GET",headers:{Accept:"application/json",Authorization:`Bearer ${n.token}`}});if(!o.ok)return C(o);const a=await o.json();return c("Cameras fetched:",a.results?.length??0,"cameras"),_(a)}catch(o){return i("NETWORK_ERROR",`Failed to fetch cameras: ${String(o)}`)}}async function pe(e,n){const t=g();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 s=r.toString(),o=`${t.baseUrl}/api/v3.0/cameras/${encodeURIComponent(e)}${s?`?${s}`:""}`;c("Fetching camera:",o);try{const a=await fetch(o,{method:"GET",headers:{Accept:"application/json",Authorization:`Bearer ${t.token}`}});if(!a.ok)return C(a);const l=await a.json();return c("Camera fetched:",l.name),_(l)}catch(a){return i("NETWORK_ERROR",`Failed to fetch camera: ${String(a)}`)}}async function C(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)}}async function Te(e){const n=g();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?.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(),s=`${n.baseUrl}/api/v3.0/bridges${r?`?${r}`:""}`;c("Fetching bridges:",s);try{const o=await fetch(s,{method:"GET",headers:{Accept:"application/json",Authorization:`Bearer ${n.token}`}});if(!o.ok)return H(o);const a=await o.json();return c("Bridges fetched:",a.results?.length??0,"bridges"),_(a)}catch(o){return i("NETWORK_ERROR",`Failed to fetch bridges: ${String(o)}`)}}async function Ee(e,n){const t=g();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","Bridge ID is required");const r=new URLSearchParams;n?.include&&n.include.length>0&&r.append("include",n.include.join(","));const s=r.toString(),o=`${t.baseUrl}/api/v3.0/bridges/${encodeURIComponent(e)}${s?`?${s}`:""}`;c("Fetching bridge:",o);try{const a=await fetch(o,{method:"GET",headers:{Accept:"application/json",Authorization:`Bearer ${t.token}`}});if(!a.ok)return H(a);const l=await a.json();return c("Bridge fetched:",l.name),_(l)}catch(a){return i("NETWORK_ERROR",`Failed to fetch bridge: ${String(a)}`)}}async function H(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)}}const Ae=3e4;function w(e=Ae){const n=new AbortController,t=setTimeout(()=>n.abort(),e);return{controller:n,timeoutId:t}}function z(e){const n=new Uint8Array(e),t=8192,r=[];for(let o=0;o<n.byteLength;o+=t){const a=n.subarray(o,Math.min(o+t,n.byteLength));r.push(String.fromCharCode.apply(null,a))}const s=r.join("");return typeof btoa=="function"?btoa(s):Buffer.from(s,"binary").toString("base64")}async function ve(e){const n=g();if(!n.isAuthenticated)return i("AUTH_REQUIRED","Authentication required");if(!n.baseUrl)return i("AUTH_REQUIRED","Base URL not configured");if(!e.deviceId)return i("VALIDATION_ERROR","Device ID is required");if(!e.type)return i("VALIDATION_ERROR","Stream type is required (preview or main)");if(!e.mediaType)return i("VALIDATION_ERROR","Media type is required (video or image)");if(!e.startTimestamp)return i("VALIDATION_ERROR","Start timestamp is required");const t=new URLSearchParams;t.append("deviceId",e.deviceId),t.append("type",e.type),t.append("mediaType",e.mediaType),t.append("startTimestamp__gte",e.startTimestamp),e.endTimestamp&&t.append("endTimestamp__lte",e.endTimestamp),typeof e.coalesce=="boolean"&&t.append("coalesce",String(e.coalesce)),e.include&&e.include.length>0&&t.append("include",e.include.join(",")),e.pageToken&&t.append("pageToken",e.pageToken),typeof e.pageSize=="number"&&t.append("pageSize",String(e.pageSize));const r=`${n.baseUrl}/api/v3.0/media?${t.toString()}`;c("Fetching media intervals:",r);const{controller:s,timeoutId:o}=w();try{const a=await fetch(r,{method:"GET",headers:{Accept:"application/json",Authorization:`Bearer ${n.token}`},signal:s.signal});if(!a.ok)return L(a);const l=await a.json();return c("Media intervals fetched:",l.results?.length??0,"intervals"),_(l)}catch(a){return a instanceof Error&&a.name==="AbortError"?i("NETWORK_ERROR","Request timed out"):i("NETWORK_ERROR",`Failed to fetch media intervals: ${String(a)}`)}finally{clearTimeout(o)}}async function Ue(e){const n=g();if(!n.isAuthenticated)return i("AUTH_REQUIRED","Authentication required");if(!n.baseUrl)return i("AUTH_REQUIRED","Base URL not configured");if(!e.deviceId)return i("VALIDATION_ERROR","Device ID is required");const t=e.type??"preview",r=new URLSearchParams;r.append("deviceId",e.deviceId),r.append("type",t);const s=`${n.baseUrl}/api/v3.0/media/liveImage.jpeg?${r.toString()}`;c("Fetching live image:",s);const{controller:o,timeoutId:a}=w();try{const l=await fetch(s,{method:"GET",headers:{Accept:"image/jpeg",Authorization:`Bearer ${n.token}`},signal:o.signal}),p=l.headers.get("X-Een-Timestamp"),R=l.headers.get("X-Een-PrevToken");if(!l.ok)return L(l);const h=await l.arrayBuffer(),U=`data:image/jpeg;base64,${z(h)}`;return c("Live image fetched, timestamp:",p),_({imageData:U,timestamp:p,prevToken:R})}catch(l){return l instanceof Error&&l.name==="AbortError"?i("NETWORK_ERROR","Request timed out"):i("NETWORK_ERROR",`Failed to fetch live image: ${String(l)}`)}finally{clearTimeout(a)}}async function Se(e){const n=g();if(!n.isAuthenticated)return i("AUTH_REQUIRED","Authentication required");if(!n.baseUrl)return i("AUTH_REQUIRED","Base URL not configured");if(!e.deviceId&&!e.pageToken)return i("VALIDATION_ERROR","Either deviceId or pageToken is required");if(!e.pageToken&&!(e.timestamp__lt||e.timestamp__lte||e.timestamp||e.timestamp__gte||e.timestamp__gt))return i("VALIDATION_ERROR","At least one timestamp parameter is required");if(e.include?.includes("overlaySvgHeader")&&(!e.overlayId__in||e.overlayId__in.length===0))return i("VALIDATION_ERROR","At least one overlayId must be provided when requesting overlay headers");const t=new URLSearchParams;e.deviceId&&t.append("deviceId",e.deviceId),e.pageToken&&t.append("pageToken",e.pageToken),e.type&&t.append("type",e.type),e.timestamp__lt&&t.append("timestamp__lt",e.timestamp__lt),e.timestamp__lte&&t.append("timestamp__lte",e.timestamp__lte),e.timestamp&&t.append("timestamp",e.timestamp),e.timestamp__gte&&t.append("timestamp__gte",e.timestamp__gte),e.timestamp__gt&&t.append("timestamp__gt",e.timestamp__gt),e.overlayId__in&&e.overlayId__in.length>0&&t.append("overlayId__in",e.overlayId__in.join(",")),e.include&&e.include.length>0&&t.append("include",e.include.join(",")),typeof e.targetWidth=="number"&&t.append("targetWidth",String(e.targetWidth)),typeof e.targetHeight=="number"&&t.append("targetHeight",String(e.targetHeight));const r=`${n.baseUrl}/api/v3.0/media/recordedImage.jpeg?${t.toString()}`;c("Fetching recorded image:",r);const{controller:s,timeoutId:o}=w();try{const a=await fetch(r,{method:"GET",headers:{Accept:"image/jpeg",Authorization:`Bearer ${n.token}`},signal:s.signal}),l=a.headers.get("X-Een-Timestamp"),p=a.headers.get("X-Een-NextToken"),R=a.headers.get("X-Een-PrevToken"),h=a.headers.get("X-Een-OverlaySvg");if(!a.ok)return L(a);const I=await a.arrayBuffer(),S=`data:image/jpeg;base64,${z(I)}`;return c("Recorded image fetched, timestamp:",l),_({imageData:S,timestamp:l,nextToken:p,prevToken:R,overlaySvg:h})}catch(a){return a instanceof Error&&a.name==="AbortError"?i("NETWORK_ERROR","Request timed out"):i("NETWORK_ERROR",`Failed to fetch recorded image: ${String(a)}`)}finally{clearTimeout(o)}}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 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);case 503:return i("SERVICE_UNAVAILABLE",`Service unavailable: ${t}`,n);default:return i("API_ERROR",`API error: ${t}`,n)}}async function ye(e){const n=g();if(!n.isAuthenticated)return i("AUTH_REQUIRED","Authentication required");if(!n.baseUrl)return i("AUTH_REQUIRED","Base URL not configured");const t=new URLSearchParams;typeof e?.pageSize=="number"&&t.append("pageSize",String(e.pageSize)),e?.pageToken&&t.append("pageToken",e.pageToken),e?.deviceId&&t.append("deviceId",e.deviceId),e?.deviceId__in&&e.deviceId__in.length>0&&t.append("deviceId__in",e.deviceId__in.join(",")),e?.type&&t.append("type",e.type),e?.include&&e.include.length>0&&t.append("include",e.include.join(","));const r=t.toString(),s=`${n.baseUrl}/api/v3.0/feeds${r?`?${r}`:""}`;c("Fetching feeds:",s);try{const o=await fetch(s,{method:"GET",headers:{Accept:"application/json",Authorization:`Bearer ${n.token}`},signal:e?.signal});if(!o.ok)return ke(o);const a=await o.json();return c("Feeds fetched:",a.results?.length??0,"feeds"),_(a)}catch(o){return i("NETWORK_ERROR",`Failed to fetch feeds: ${String(o)}`)}}async function ke(e){const n=e.status;let t;try{const r=await e.json();t=r.message??r.error}catch(r){c("Failed to parse error response JSON:",r)}switch(n){case 401:return i("AUTH_REQUIRED",t||"Authentication failed",n);case 403:return i("FORBIDDEN",t||"Access denied",n);case 404:return i("NOT_FOUND",t||"Not found",n);case 429:return i("RATE_LIMITED",t||"Rate limited",n);case 503:return i("SERVICE_UNAVAILABLE",t||"Service unavailable",n);default:return i("API_ERROR",t||e.statusText||"API error",n)}}exports.failure=i;exports.getAccessToken=O;exports.getAuthUrl=P;exports.getBridge=Ee;exports.getBridges=Te;exports.getCamera=pe;exports.getCameras=Ie;exports.getClientId=F;exports.getConfig=se;exports.getCurrentUser=ge;exports.getLiveImage=Ue;exports.getProxyUrl=y;exports.getRecordedImage=Se;exports.getRedirectUri=$;exports.getUser=Re;exports.getUsers=he;exports.handleAuthCallback=B;exports.initEenToolkit=ae;exports.listFeeds=ye;exports.listMedia=ve;exports.refreshToken=q;exports.revokeToken=x;exports.success=_;exports.useAuthStore=g;
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|