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
@@ -1,20 +1,54 @@
1
1
  <script setup lang="ts">
2
+ import { ref, onMounted, watch } from 'vue'
2
3
  import { useRoute } from 'vue-router'
3
- import { useCamera, type CameraStatus } from 'een-api-toolkit'
4
+ import { getCamera, type Camera, type CameraStatus, type EenError } from 'een-api-toolkit'
4
5
 
5
6
  const route = useRoute()
6
7
 
7
- // Fetch camera with all details
8
- const { camera, loading, error, refresh } = useCamera(
9
- () => route.params.id as string,
10
- {
8
+ // Reactive state
9
+ const camera = ref<Camera | null>(null)
10
+ const loading = ref(false)
11
+ const error = ref<EenError | null>(null)
12
+
13
+ async function fetchCamera() {
14
+ const id = route.params.id as string
15
+ if (!id) {
16
+ error.value = { code: 'VALIDATION_ERROR', message: 'Camera ID is required' }
17
+ return
18
+ }
19
+
20
+ loading.value = true
21
+ error.value = null
22
+
23
+ const result = await getCamera(id, {
11
24
  include: ['deviceInfo', 'status', 'shareDetails', 'devicePosition', 'networkInfo', 'tags']
25
+ })
26
+
27
+ if (result.error) {
28
+ error.value = result.error
29
+ camera.value = null
30
+ } else {
31
+ camera.value = result.data
12
32
  }
13
- )
33
+
34
+ loading.value = false
35
+ }
36
+
37
+ function refresh() {
38
+ return fetchCamera()
39
+ }
40
+
41
+ // Helper to extract status string from the union type
42
+ function getStatusString(status?: CameraStatus | { connectionStatus?: CameraStatus }): CameraStatus | undefined {
43
+ if (!status) return undefined
44
+ if (typeof status === 'string') return status
45
+ return status.connectionStatus
46
+ }
14
47
 
15
48
  // Get status badge class
16
- function getStatusClass(status?: CameraStatus): string {
17
- switch (status) {
49
+ function getStatusClass(status?: CameraStatus | { connectionStatus?: CameraStatus }): string {
50
+ const statusStr = getStatusString(status)
51
+ switch (statusStr) {
18
52
  case 'online':
19
53
  case 'streaming':
20
54
  return 'status-online'
@@ -29,6 +63,20 @@ function getStatusClass(status?: CameraStatus): string {
29
63
  return 'status-unknown'
30
64
  }
31
65
  }
66
+
67
+ onMounted(() => {
68
+ fetchCamera()
69
+ })
70
+
71
+ // Watch for route param changes
72
+ watch(
73
+ () => route.params.id,
74
+ (newId, oldId) => {
75
+ if (newId && newId !== oldId) {
76
+ fetchCamera()
77
+ }
78
+ }
79
+ )
32
80
  </script>
33
81
 
34
82
  <template>
@@ -53,7 +101,7 @@ function getStatusClass(status?: CameraStatus): string {
53
101
  </div>
54
102
  <div class="header-actions">
55
103
  <span :class="['status-badge', getStatusClass(camera.status)]">
56
- {{ camera.status || 'Unknown' }}
104
+ {{ getStatusString(camera.status) || 'Unknown' }}
57
105
  </span>
58
106
  <button @click="refresh">Refresh</button>
59
107
  </div>
@@ -1,26 +1,65 @@
1
1
  <script setup lang="ts">
2
- import { ref, watch } from 'vue'
3
- import { useCameras, type CameraStatus } from 'een-api-toolkit'
2
+ import { ref, computed, watch, onMounted } from 'vue'
3
+ import { getCameras, type Camera, type CameraStatus, type EenError, type ListCamerasParams } from 'een-api-toolkit'
4
4
 
5
5
  // Status filter
6
6
  const statusFilter = ref<CameraStatus | ''>('')
7
7
 
8
- // Initial fetch with common includes
9
- const {
10
- cameras,
11
- loading,
12
- error,
13
- hasNextPage,
14
- totalSize,
15
- fetchNextPage,
16
- refresh,
17
- setParams,
18
- fetch
19
- } = useCameras({
8
+ // Reactive state
9
+ const cameras = ref<Camera[]>([])
10
+ const loading = ref(false)
11
+ const error = ref<EenError | null>(null)
12
+ const nextPageToken = ref<string | undefined>(undefined)
13
+ const totalSize = ref<number | undefined>(undefined)
14
+
15
+ const hasNextPage = computed(() => !!nextPageToken.value)
16
+
17
+ const params = ref<ListCamerasParams>({
20
18
  pageSize: 20,
21
19
  include: ['deviceInfo', 'status']
22
20
  })
23
21
 
22
+ async function fetchCameras(fetchParams?: ListCamerasParams, append = false) {
23
+ loading.value = true
24
+ error.value = null
25
+
26
+ const mergedParams = { ...params.value, ...fetchParams }
27
+ const result = await getCameras(mergedParams)
28
+
29
+ if (result.error) {
30
+ error.value = result.error
31
+ if (!append) {
32
+ cameras.value = []
33
+ totalSize.value = undefined
34
+ }
35
+ nextPageToken.value = undefined
36
+ } else {
37
+ if (append) {
38
+ cameras.value = [...cameras.value, ...result.data.results]
39
+ } else {
40
+ cameras.value = result.data.results
41
+ }
42
+ nextPageToken.value = result.data.nextPageToken
43
+ totalSize.value = result.data.totalSize
44
+ }
45
+
46
+ loading.value = false
47
+ return result
48
+ }
49
+
50
+ function refresh() {
51
+ return fetchCameras()
52
+ }
53
+
54
+ async function fetchNextPage() {
55
+ if (!nextPageToken.value) return
56
+ return fetchCameras({ ...params.value, pageToken: nextPageToken.value }, true)
57
+ }
58
+
59
+ function setParams(newParams: ListCamerasParams) {
60
+ params.value = newParams
61
+ }
62
+
24
63
  // Watch for status filter changes
25
64
  watch(statusFilter, async (newStatus) => {
26
65
  if (newStatus) {
@@ -35,12 +74,20 @@ watch(statusFilter, async (newStatus) => {
35
74
  include: ['deviceInfo', 'status']
36
75
  })
37
76
  }
38
- await fetch()
77
+ await fetchCameras()
39
78
  })
40
79
 
80
+ // Helper to extract status string from the union type
81
+ function getStatusString(status?: CameraStatus | { connectionStatus?: CameraStatus }): CameraStatus | undefined {
82
+ if (!status) return undefined
83
+ if (typeof status === 'string') return status
84
+ return status.connectionStatus
85
+ }
86
+
41
87
  // Get status badge class
42
- function getStatusClass(status?: CameraStatus): string {
43
- switch (status) {
88
+ function getStatusClass(status?: CameraStatus | { connectionStatus?: CameraStatus }): string {
89
+ const statusStr = getStatusString(status)
90
+ switch (statusStr) {
44
91
  case 'online':
45
92
  case 'streaming':
46
93
  return 'status-online'
@@ -55,6 +102,10 @@ function getStatusClass(status?: CameraStatus): string {
55
102
  return 'status-unknown'
56
103
  }
57
104
  }
105
+
106
+ onMounted(() => {
107
+ fetchCameras()
108
+ })
58
109
  </script>
59
110
 
60
111
  <template>
@@ -100,7 +151,7 @@ function getStatusClass(status?: CameraStatus): string {
100
151
  <div class="camera-header">
101
152
  <h3>{{ camera.name }}</h3>
102
153
  <span :class="['status-badge', getStatusClass(camera.status)]">
103
- {{ camera.status || 'Unknown' }}
154
+ {{ getStatusString(camera.status) || 'Unknown' }}
104
155
  </span>
105
156
  </div>
106
157
  <div class="camera-details">
@@ -1,45 +1,70 @@
1
1
  <script setup lang="ts">
2
- import { useAuthStore, useCurrentUser } from 'een-api-toolkit'
3
- import { computed } from 'vue'
2
+ import { useAuthStore, getCurrentUser, type UserProfile, type EenError } from 'een-api-toolkit'
3
+ import { computed, ref, onMounted } from 'vue'
4
4
 
5
5
  const authStore = useAuthStore()
6
6
  const isAuthenticated = computed(() => authStore.isAuthenticated)
7
7
 
8
- // Fetch current user if authenticated
9
- const { user, loading, error } = useCurrentUser({ immediate: true })
8
+ // Reactive state for current user
9
+ const user = ref<UserProfile | null>(null)
10
+ const loading = ref(false)
11
+ const error = ref<EenError | null>(null)
12
+
13
+ async function fetchUser() {
14
+ if (!isAuthenticated.value) return
15
+
16
+ loading.value = true
17
+ error.value = null
18
+
19
+ const result = await getCurrentUser()
20
+ if (result.error) {
21
+ error.value = result.error
22
+ user.value = null
23
+ } else {
24
+ user.value = result.data
25
+ }
26
+
27
+ loading.value = false
28
+ }
29
+
30
+ onMounted(() => {
31
+ if (isAuthenticated.value) {
32
+ fetchUser()
33
+ }
34
+ })
10
35
  </script>
11
36
 
12
37
  <template>
13
38
  <div class="home">
14
39
  <h2>Welcome to the EEN Cameras Example</h2>
15
40
 
16
- <div v-if="isAuthenticated">
41
+ <div v-if="isAuthenticated" data-testid="authenticated">
17
42
  <div v-if="loading" class="loading">Loading user info...</div>
18
43
  <div v-else-if="error" class="error">{{ error.message }}</div>
19
- <div v-else-if="user" class="user-info">
44
+ <div v-else-if="user" class="user-info" data-testid="user-info">
20
45
  <p>Logged in as: <strong>{{ user.firstName }} {{ user.lastName }}</strong></p>
21
46
  <p>Email: {{ user.email }}</p>
22
47
  </div>
23
48
 
24
49
  <div class="actions">
25
50
  <router-link to="/cameras">
26
- <button>View Cameras</button>
51
+ <button data-testid="view-cameras-button">View Cameras</button>
27
52
  </router-link>
28
53
  </div>
29
54
  </div>
30
55
 
31
- <div v-else class="login-prompt">
56
+ <div v-else class="login-prompt" data-testid="not-authenticated">
32
57
  <p>Please log in to view your cameras.</p>
33
58
  <router-link to="/login">
34
- <button>Login</button>
59
+ <button data-testid="login-button">Login</button>
35
60
  </router-link>
36
61
  </div>
37
62
 
38
63
  <div class="description">
39
64
  <h3>About This Example</h3>
40
65
  <p>
41
- This example demonstrates how to use the <code>useCameras</code> and
42
- <code>useCamera</code> composables from the EEN API Toolkit to display
66
+ This example demonstrates how to use the <code>getCameras</code> and
67
+ <code>getCamera</code> functions from the EEN API Toolkit to display
43
68
  and manage cameras from the Eagle Eye Networks platform.
44
69
  </p>
45
70
  <h4>Features</h4>
@@ -1,4 +1,4 @@
1
- # EEN API Toolkit - Vue 3 Example
1
+ # EEN API Toolkit - Vue Users Example
2
2
 
3
3
  A complete example showing how to use the een-api-toolkit in a Vue 3 application.
4
4
 
@@ -30,11 +30,11 @@ A complete example showing how to use the een-api-toolkit in a Vue 3 application
30
30
 
31
31
  ### Example Setup
32
32
 
33
- All commands below should be run from this example directory (`examples/vue-basic/`):
33
+ All commands below should be run from this example directory (`examples/vue-users/`):
34
34
 
35
35
  2. Copy the environment file:
36
36
  ```bash
37
- # From examples/vue-basic/
37
+ # From examples/vue-users/
38
38
  cp .env.example .env
39
39
  ```
40
40
 
@@ -48,7 +48,7 @@ All commands below should be run from this example directory (`examples/vue-basi
48
48
 
49
49
  4. Install dependencies and start:
50
50
  ```bash
51
- # From examples/vue-basic/
51
+ # From examples/vue-users/
52
52
  npm install
53
53
  npm run dev
54
54
  ```
@@ -1,16 +1,16 @@
1
1
  import { test, expect } from '@playwright/test'
2
2
 
3
- test.describe('Vue Basic Example - App', () => {
3
+ test.describe('Vue Users Example - App', () => {
4
4
  test.beforeEach(async ({ page }) => {
5
5
  await page.goto('/')
6
6
  })
7
7
 
8
8
  test('app loads with correct title', async ({ page }) => {
9
- await expect(page).toHaveTitle(/EEN API Toolkit/)
9
+ await expect(page).toHaveTitle(/EEN Users/)
10
10
  })
11
11
 
12
12
  test('header displays app name', async ({ page }) => {
13
- await expect(page.locator('[data-testid="app-title"]')).toHaveText('EEN API Toolkit Example')
13
+ await expect(page.locator('[data-testid="app-title"]')).toHaveText('EEN Users Example')
14
14
  })
15
15
 
16
16
  test('navigation shows Home and Login links when not authenticated', async ({ page }) => {
@@ -1,7 +1,7 @@
1
1
  import { test, expect, Page } from '@playwright/test'
2
2
 
3
3
  /**
4
- * E2E tests for the Vue Basic Example
4
+ * E2E tests for the Vue Users Example
5
5
  *
6
6
  * Tests the OAuth login flow through the UI:
7
7
  * 1. Click login button in the example app
@@ -111,7 +111,7 @@ async function clearAuthState(page: Page): Promise<void> {
111
111
  }
112
112
  }
113
113
 
114
- test.describe('Vue Basic Example', () => {
114
+ test.describe('Vue Users Example', () => {
115
115
  // Check proxy accessibility once before all tests
116
116
  let proxyAccessible = false
117
117
 
@@ -4,7 +4,7 @@
4
4
  <meta charset="UTF-8" />
5
5
  <link rel="icon" type="image/svg+xml" href="/vite.svg" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
- <title>EEN API Toolkit Example</title>
7
+ <title>EEN Users Example</title>
8
8
  </head>
9
9
  <body>
10
10
  <div id="app"></div>
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "een-api-toolkit-example",
3
- "version": "0.0.8",
3
+ "version": "0.0.12",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "een-api-toolkit-example",
9
- "version": "0.0.8",
9
+ "version": "0.0.12",
10
10
  "dependencies": {
11
11
  "een-api-toolkit": "file:../..",
12
12
  "pinia": "^2.1.7",
@@ -23,7 +23,7 @@
23
23
  }
24
24
  },
25
25
  "../..": {
26
- "version": "0.0.11",
26
+ "version": "0.1.1",
27
27
  "license": "MIT",
28
28
  "devDependencies": {
29
29
  "@playwright/test": "^1.57.0",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "een-api-toolkit-example",
3
- "version": "0.0.8",
3
+ "version": "0.0.12",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "scripts": {
@@ -9,7 +9,7 @@ const isAuthenticated = computed(() => authStore.isAuthenticated)
9
9
  <template>
10
10
  <div class="app">
11
11
  <header>
12
- <h1 data-testid="app-title">EEN API Toolkit Example</h1>
12
+ <h1 data-testid="app-title">EEN Users Example</h1>
13
13
  <nav>
14
14
  <router-link data-testid="nav-home" to="/">Home</router-link>
15
15
  <router-link data-testid="nav-users" v-if="isAuthenticated" to="/users">Users</router-link>
@@ -1,5 +1,5 @@
1
1
  <script setup lang="ts">
2
- import { useAuthStore, useCurrentUser, getAuthUrl } from 'een-api-toolkit'
2
+ import { useAuthStore, getCurrentUser, getAuthUrl, type UserProfile, type EenError } from 'een-api-toolkit'
3
3
  import { computed, ref, watch } from 'vue'
4
4
 
5
5
  const authStore = useAuthStore()
@@ -17,25 +17,40 @@ function login() {
17
17
  }
18
18
  }
19
19
 
20
- // Don't fetch on mount - we'll handle it reactively
21
- const { user, loading, error, fetch } = useCurrentUser({
22
- immediate: false
23
- })
20
+ // Reactive state for current user
21
+ const user = ref<UserProfile | null>(null)
22
+ const loading = ref(false)
23
+ const error = ref<EenError | null>(null)
24
24
 
25
25
  // Guard to prevent concurrent fetch calls
26
26
  let fetchInProgress = false
27
27
 
28
+ async function fetchUser() {
29
+ if (fetchInProgress) return
30
+ fetchInProgress = true
31
+ loading.value = true
32
+ error.value = null
33
+
34
+ try {
35
+ const result = await getCurrentUser()
36
+ if (result.error) {
37
+ error.value = result.error
38
+ user.value = null
39
+ } else {
40
+ user.value = result.data
41
+ }
42
+ } finally {
43
+ loading.value = false
44
+ fetchInProgress = false
45
+ }
46
+ }
47
+
28
48
  // Fetch user when authentication state changes
29
49
  watch(
30
50
  isAuthenticated,
31
51
  async (isAuth) => {
32
52
  if (isAuth && !user.value && !fetchInProgress) {
33
- fetchInProgress = true
34
- try {
35
- await fetch()
36
- } finally {
37
- fetchInProgress = false
38
- }
53
+ await fetchUser()
39
54
  }
40
55
  },
41
56
  { immediate: true }
@@ -44,7 +59,7 @@ watch(
44
59
 
45
60
  <template>
46
61
  <div class="home">
47
- <h2>Welcome to the EEN API Toolkit Example</h2>
62
+ <h2>Welcome to the EEN Users Example</h2>
48
63
 
49
64
  <div v-if="!isAuthenticated" class="not-authenticated" data-testid="not-authenticated">
50
65
  <p data-testid="not-authenticated-message">You are not logged in.</p>
@@ -1,14 +1,55 @@
1
1
  <script setup lang="ts">
2
- import { useUsers } from 'een-api-toolkit'
3
-
4
- const {
5
- users,
6
- loading,
7
- error,
8
- hasNextPage,
9
- fetchNextPage,
10
- refresh
11
- } = useUsers({ pageSize: 10 })
2
+ import { ref, computed, onMounted } from 'vue'
3
+ import { getUsers, type User, type EenError, type ListUsersParams } from 'een-api-toolkit'
4
+
5
+ // Reactive state
6
+ const users = ref<User[]>([])
7
+ const loading = ref(false)
8
+ const error = ref<EenError | null>(null)
9
+ const nextPageToken = ref<string | undefined>(undefined)
10
+
11
+ const hasNextPage = computed(() => !!nextPageToken.value)
12
+
13
+ const params = ref<ListUsersParams>({ pageSize: 10 })
14
+
15
+ async function fetchUsers(fetchParams?: ListUsersParams, append = false) {
16
+ loading.value = true
17
+ error.value = null
18
+
19
+ const mergedParams = { ...params.value, ...fetchParams }
20
+ const result = await getUsers(mergedParams)
21
+
22
+ if (result.error) {
23
+ error.value = result.error
24
+ if (!append) {
25
+ users.value = []
26
+ }
27
+ nextPageToken.value = undefined
28
+ } else {
29
+ if (append) {
30
+ users.value = [...users.value, ...result.data.results]
31
+ } else {
32
+ users.value = result.data.results
33
+ }
34
+ nextPageToken.value = result.data.nextPageToken
35
+ }
36
+
37
+ loading.value = false
38
+ return result
39
+ }
40
+
41
+ function refresh() {
42
+ return fetchUsers()
43
+ }
44
+
45
+ async function fetchNextPage() {
46
+ if (!nextPageToken.value) return
47
+ return fetchUsers({ ...params.value, pageToken: nextPageToken.value }, true)
48
+ }
49
+
50
+ onMounted(() => {
51
+ fetchUsers()
52
+ })
12
53
  </script>
13
54
 
14
55
  <template>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "een-api-toolkit",
3
- "version": "0.0.18",
3
+ "version": "0.1.2",
4
4
  "description": "EEN Video platform API v3.0 library for Vue 3",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
File without changes
File without changes
File without changes