een-api-toolkit 0.1.13 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,23 +2,60 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
- ## [0.1.13] - 2026-01-01
5
+ ## [0.2.0] - 2026-01-02
6
6
 
7
7
  ### Release Summary
8
8
 
9
- No PR descriptions available for this release.
9
+ #### PR #39: Release v0.1.13: Documentation updates and example improvements
10
+ ## Summary
10
11
 
11
- ### Detailed Changes
12
+ This release includes documentation improvements and developer experience enhancements:
13
+
14
+ - **Example README files**: Added comprehensive README.md files with screenshots for all 5 example applications (vue-bridges, vue-cameras, vue-feeds, vue-media, vue-users)
15
+ - **Faster dev server startup**: Replaced slow `npx kill-port` (10-15 seconds) with native `lsof` command for instant port cleanup
16
+ - **Documentation fixes**: Fixed vue-users README to use functions instead of removed composables, updated docs/README.md to reference all example apps
17
+
18
+ ## Commits included
19
+
20
+ - 9050e88 docs: Update README.md to reference all example apps
21
+ - 105051e docs: Fix vue-users README to use functions instead of composables
22
+ - 8d11c7a chore: Replace npx kill-port with faster native lsof command
23
+ - 741ca61 docs: Add README files and screenshots to example applications
24
+ - f4aa78b Merge pull request #38 from klaushofrichter/develop
25
+ - 6f3b0bf fix: Address code review feedback from PR #38
26
+ - 0432d7a feat: Add Media Session API and live video streaming to vue-feeds
27
+
28
+ ## Test Results
29
+
30
+ - ✅ Lint: Passed (1 expected warning for unused vars in test files)
31
+ - ✅ Unit tests: 164 passed
32
+ - ✅ Build: Succeeded
12
33
 
13
- #### Features
14
- - feat: Add Media Session API and live video streaming to vue-feeds
34
+ ## Version
35
+
36
+ **0.1.13**
37
+
38
+ 🤖 Generated with [Claude Code](https://claude.com/claude-code)
39
+
40
+
41
+ ### Detailed Changes
15
42
 
16
43
  #### Bug Fixes
17
- - fix: Address code review feedback from PR #38
44
+ - fix: Address remaining code review recommendations
45
+ - fix: Address code review feedback for PR #40
46
+ - fix: Address code review feedback - macOS note, xargs safety, and skill fix
47
+
48
+ #### Other Changes
49
+ - chore: Bump version to 0.2.0 and add CHANGELOG
50
+ - chore: Update dependencies and fix E2E tests
51
+ - docs: Update README.md to reference all example apps
52
+ - docs: Fix vue-users README to use functions instead of composables
53
+ - chore: Replace npx kill-port with faster native lsof command
54
+ - docs: Add README files and screenshots to example applications
18
55
 
19
56
  ### Links
20
57
  - [npm package](https://www.npmjs.com/package/een-api-toolkit)
21
- - [Full Changelog](https://github.com/klaushofrichter/een-api-toolkit/compare/v0.1.10...v0.1.13)
58
+ - [Full Changelog](https://github.com/klaushofrichter/een-api-toolkit/compare/v0.1.13...v0.2.0)
22
59
 
23
60
  ---
24
- *Released: 2026-01-01 20:18:29 CST*
61
+ *Released: 2026-01-02 09:30:09 CST*
package/README.md CHANGED
@@ -199,6 +199,44 @@ npm run dev # Runs at http://127.0.0.1:3333
199
199
 
200
200
  > **Note:** Examples require a running OAuth proxy. See [Quick Start](#2-set-up-oauth-proxy).
201
201
 
202
+ ## Running E2E Tests
203
+
204
+ Each example includes Playwright E2E tests that test the full OAuth login flow. Tests are designed to skip gracefully when the OAuth proxy or credentials are unavailable.
205
+
206
+ ### Prerequisites
207
+
208
+ 1. **OAuth Proxy**: Start the proxy server:
209
+ ```bash
210
+ ./scripts/restart-proxy.sh # Starts proxy at http://127.0.0.1:8787
211
+ ```
212
+
213
+ 2. **Environment Variables**: Create a `.env` file in the project root:
214
+ ```bash
215
+ VITE_PROXY_URL=http://127.0.0.1:8787
216
+ VITE_EEN_CLIENT_ID=your_client_id
217
+ TEST_USER=your_test_email
218
+ TEST_PASSWORD=your_test_password
219
+ ```
220
+
221
+ ### Running Tests
222
+
223
+ ```bash
224
+ # Run E2E tests for a specific example
225
+ cd examples/vue-users
226
+ npm run test:e2e
227
+
228
+ # Run with UI for debugging
229
+ npm run test:e2e:ui
230
+ ```
231
+
232
+ ### Test Behavior
233
+
234
+ - **Proxy unavailable**: OAuth tests are automatically skipped with message "OAuth proxy not accessible"
235
+ - **Credentials missing**: OAuth tests are skipped with message "Test credentials not available"
236
+ - **Basic tests**: Tests that don't require OAuth (e.g., checking login button visibility) always run
237
+
238
+ > **Note:** All development and testing has been done on macOS. The `lsof` command used in scripts may behave differently on other platforms.
239
+
202
240
  ## External Resources
203
241
 
204
242
  - [EEN Developer Portal](https://developer.eagleeyenetworks.com/)
@@ -1,6 +1,6 @@
1
1
  # EEN API Toolkit - AI Reference
2
2
 
3
- > **Version:** 0.1.13
3
+ > **Version:** 0.2.0
4
4
  >
5
5
  > This file is optimized for AI assistants. It contains all API signatures,
6
6
  > types, and usage patterns in a single, parseable document.
@@ -0,0 +1,126 @@
1
+ # EEN API Toolkit - Vue Bridges Example
2
+
3
+ A Vue 3 example demonstrating how to list and view EEN bridge devices using the een-api-toolkit.
4
+
5
+ ![Bridges Screenshot](bridges-screenshot.png)
6
+
7
+ ## Features Demonstrated
8
+
9
+ - OAuth authentication flow (login, callback, logout)
10
+ - Protected routes with navigation guards
11
+ - `getBridges()` function for listing bridges with pagination
12
+ - `getBridge()` function for fetching bridge details
13
+ - Status filtering (online, offline, error, idle)
14
+ - Bridge card grid with status badges
15
+ - Detailed bridge view with device info and network info
16
+
17
+ ## APIs Used
18
+
19
+ - `getBridges()` - List bridges with filtering and pagination
20
+ - `getBridge()` - Get single bridge by ID
21
+ - `useAuthStore()` - Authentication state management
22
+ - `initEenToolkit()` - Toolkit initialization
23
+
24
+ ## Setup
25
+
26
+ ### Prerequisites
27
+
28
+ 1. **Start the OAuth proxy** (required for authentication):
29
+
30
+ The OAuth proxy is a separate project that handles token management securely.
31
+ Clone and run it from: https://github.com/klaushofrichter/een-oauth-proxy
32
+
33
+ ```bash
34
+ # In a separate terminal, from the een-oauth-proxy directory
35
+ npm install
36
+ npm run dev
37
+ ```
38
+
39
+ The proxy should be running at `http://localhost:8787`.
40
+
41
+ ### Example Setup
42
+
43
+ All commands below should be run from this example directory (`examples/vue-bridges/`):
44
+
45
+ 2. Copy the environment file:
46
+ ```bash
47
+ # From examples/vue-bridges/
48
+ cp .env.example .env
49
+ ```
50
+
51
+ 3. Edit `.env` with your EEN credentials:
52
+ ```env
53
+ VITE_EEN_CLIENT_ID=your-client-id
54
+ VITE_PROXY_URL=http://localhost:8787
55
+ # DO NOT change the redirect URI - EEN IDP only permits this URL
56
+ VITE_REDIRECT_URI=http://127.0.0.1:3333
57
+ ```
58
+
59
+ 4. Install dependencies and start:
60
+ ```bash
61
+ # From examples/vue-bridges/
62
+ npm install
63
+ npm run dev
64
+ ```
65
+
66
+ 5. Open http://127.0.0.1:3333 in your browser.
67
+
68
+ **Important:** The EEN Identity Provider only permits `http://127.0.0.1:3333` as the OAuth redirect URI. Do not use `localhost` or other ports.
69
+
70
+ **Note:** Development and testing was done on macOS. The `npm run stop` command uses `lsof`, which is not available on Windows. Windows users should manually stop any process on port 3333 or use `npx kill-port 3333` instead.
71
+
72
+ ## Project Structure
73
+
74
+ ```
75
+ src/
76
+ ├── main.ts # App entry, toolkit initialization
77
+ ├── App.vue # Root component with navigation
78
+ ├── router/
79
+ │ └── index.ts # Vue Router with auth guards
80
+ └── views/
81
+ ├── Home.vue # Home page with login prompt
82
+ ├── Login.vue # OAuth login redirect
83
+ ├── Callback.vue # OAuth callback handler
84
+ ├── Bridges.vue # Bridge list with filtering
85
+ ├── BridgeDetail.vue # Single bridge details
86
+ └── Logout.vue # Logout handler
87
+ ```
88
+
89
+ ## Key Code Examples
90
+
91
+ ### Listing Bridges with Filtering (Bridges.vue)
92
+
93
+ ```typescript
94
+ import { getBridges, type Bridge, type ListBridgesParams } from 'een-api-toolkit'
95
+
96
+ const params = ref<ListBridgesParams>({
97
+ pageSize: 20,
98
+ include: ['deviceInfo', 'status', 'networkInfo']
99
+ })
100
+
101
+ async function fetchBridges() {
102
+ const result = await getBridges(params.value)
103
+ if (result.error) {
104
+ error.value = result.error
105
+ } else {
106
+ bridges.value = result.data.results
107
+ nextPageToken.value = result.data.nextPageToken
108
+ }
109
+ }
110
+ ```
111
+
112
+ ### Fetching Bridge Details (BridgeDetail.vue)
113
+
114
+ ```typescript
115
+ import { getBridge } from 'een-api-toolkit'
116
+
117
+ const result = await getBridge(bridgeId, {
118
+ include: ['deviceInfo', 'status', 'networkInfo']
119
+ })
120
+
121
+ if (result.error) {
122
+ error.value = result.error
123
+ } else {
124
+ bridge.value = result.data
125
+ }
126
+ ```
@@ -9,7 +9,7 @@
9
9
  "version": "0.0.1",
10
10
  "dependencies": {
11
11
  "een-api-toolkit": "file:../..",
12
- "pinia": "^2.1.7",
12
+ "pinia": "^3.0.4",
13
13
  "vue": "^3.4.0",
14
14
  "vue-router": "^4.2.0"
15
15
  },
@@ -23,21 +23,22 @@
23
23
  }
24
24
  },
25
25
  "../..": {
26
- "version": "0.1.2",
26
+ "version": "0.1.13",
27
27
  "license": "MIT",
28
28
  "devDependencies": {
29
29
  "@playwright/test": "^1.57.0",
30
- "@types/node": "^22.0.0",
31
- "@typescript-eslint/eslint-plugin": "^6.21.0",
32
- "@typescript-eslint/parser": "^6.21.0",
30
+ "@types/node": "^25.0.3",
31
+ "@typescript-eslint/eslint-plugin": "^8.51.0",
32
+ "@typescript-eslint/parser": "^8.51.0",
33
33
  "@vitejs/plugin-vue": "^6.0.0",
34
- "@vue/tsconfig": "^0.5.0",
34
+ "@vue/tsconfig": "^0.8.1",
35
35
  "dotenv": "^17.2.3",
36
- "eslint": "^8.56.0",
37
- "eslint-plugin-vue": "^9.20.0",
36
+ "eslint": "^9.39.2",
37
+ "eslint-plugin-vue": "^10.6.2",
38
+ "globals": "^17.0.0",
38
39
  "husky": "^9.1.7",
39
40
  "jsdom": "^27.4.0",
40
- "pinia": "^2.1.7",
41
+ "pinia": "^3.0.4",
41
42
  "tsx": "^4.21.0",
42
43
  "typedoc": "^0.28.15",
43
44
  "typedoc-plugin-markdown": "^4.9.0",
@@ -990,6 +991,30 @@
990
991
  "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==",
991
992
  "license": "MIT"
992
993
  },
994
+ "node_modules/@vue/devtools-kit": {
995
+ "version": "7.7.9",
996
+ "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.7.9.tgz",
997
+ "integrity": "sha512-PyQ6odHSgiDVd4hnTP+aDk2X4gl2HmLDfiyEnn3/oV+ckFDuswRs4IbBT7vacMuGdwY/XemxBoh302ctbsptuA==",
998
+ "license": "MIT",
999
+ "dependencies": {
1000
+ "@vue/devtools-shared": "^7.7.9",
1001
+ "birpc": "^2.3.0",
1002
+ "hookable": "^5.5.3",
1003
+ "mitt": "^3.0.1",
1004
+ "perfect-debounce": "^1.0.0",
1005
+ "speakingurl": "^14.0.1",
1006
+ "superjson": "^2.2.2"
1007
+ }
1008
+ },
1009
+ "node_modules/@vue/devtools-shared": {
1010
+ "version": "7.7.9",
1011
+ "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.7.9.tgz",
1012
+ "integrity": "sha512-iWAb0v2WYf0QWmxCGy0seZNDPdO3Sp5+u78ORnyeonS6MT4PC7VPrryX2BpMJrwlDeaZ6BD4vP4XKjK0SZqaeA==",
1013
+ "license": "MIT",
1014
+ "dependencies": {
1015
+ "rfdc": "^1.4.1"
1016
+ }
1017
+ },
993
1018
  "node_modules/@vue/language-core": {
994
1019
  "version": "3.2.1",
995
1020
  "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-3.2.1.tgz",
@@ -1063,6 +1088,30 @@
1063
1088
  "dev": true,
1064
1089
  "license": "MIT"
1065
1090
  },
1091
+ "node_modules/birpc": {
1092
+ "version": "2.9.0",
1093
+ "resolved": "https://registry.npmjs.org/birpc/-/birpc-2.9.0.tgz",
1094
+ "integrity": "sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==",
1095
+ "license": "MIT",
1096
+ "funding": {
1097
+ "url": "https://github.com/sponsors/antfu"
1098
+ }
1099
+ },
1100
+ "node_modules/copy-anything": {
1101
+ "version": "4.0.5",
1102
+ "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-4.0.5.tgz",
1103
+ "integrity": "sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA==",
1104
+ "license": "MIT",
1105
+ "dependencies": {
1106
+ "is-what": "^5.2.0"
1107
+ },
1108
+ "engines": {
1109
+ "node": ">=18"
1110
+ },
1111
+ "funding": {
1112
+ "url": "https://github.com/sponsors/mesqueeb"
1113
+ }
1114
+ },
1066
1115
  "node_modules/csstype": {
1067
1116
  "version": "3.2.3",
1068
1117
  "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
@@ -1179,6 +1228,24 @@
1179
1228
  "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
1180
1229
  }
1181
1230
  },
1231
+ "node_modules/hookable": {
1232
+ "version": "5.5.3",
1233
+ "resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz",
1234
+ "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==",
1235
+ "license": "MIT"
1236
+ },
1237
+ "node_modules/is-what": {
1238
+ "version": "5.5.0",
1239
+ "resolved": "https://registry.npmjs.org/is-what/-/is-what-5.5.0.tgz",
1240
+ "integrity": "sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw==",
1241
+ "license": "MIT",
1242
+ "engines": {
1243
+ "node": ">=18"
1244
+ },
1245
+ "funding": {
1246
+ "url": "https://github.com/sponsors/mesqueeb"
1247
+ }
1248
+ },
1182
1249
  "node_modules/magic-string": {
1183
1250
  "version": "0.30.21",
1184
1251
  "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
@@ -1188,6 +1255,12 @@
1188
1255
  "@jridgewell/sourcemap-codec": "^1.5.5"
1189
1256
  }
1190
1257
  },
1258
+ "node_modules/mitt": {
1259
+ "version": "3.0.1",
1260
+ "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz",
1261
+ "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==",
1262
+ "license": "MIT"
1263
+ },
1191
1264
  "node_modules/muggle-string": {
1192
1265
  "version": "0.4.1",
1193
1266
  "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.4.1.tgz",
@@ -1220,6 +1293,12 @@
1220
1293
  "dev": true,
1221
1294
  "license": "MIT"
1222
1295
  },
1296
+ "node_modules/perfect-debounce": {
1297
+ "version": "1.0.0",
1298
+ "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz",
1299
+ "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==",
1300
+ "license": "MIT"
1301
+ },
1223
1302
  "node_modules/picocolors": {
1224
1303
  "version": "1.1.1",
1225
1304
  "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
@@ -1240,20 +1319,19 @@
1240
1319
  }
1241
1320
  },
1242
1321
  "node_modules/pinia": {
1243
- "version": "2.3.1",
1244
- "resolved": "https://registry.npmjs.org/pinia/-/pinia-2.3.1.tgz",
1245
- "integrity": "sha512-khUlZSwt9xXCaTbbxFYBKDc/bWAGWJjOgvxETwkTN7KRm66EeT1ZdZj6i2ceh9sP2Pzqsbc704r2yngBrxBVug==",
1322
+ "version": "3.0.4",
1323
+ "resolved": "https://registry.npmjs.org/pinia/-/pinia-3.0.4.tgz",
1324
+ "integrity": "sha512-l7pqLUFTI/+ESXn6k3nu30ZIzW5E2WZF/LaHJEpoq6ElcLD+wduZoB2kBN19du6K/4FDpPMazY2wJr+IndBtQw==",
1246
1325
  "license": "MIT",
1247
1326
  "dependencies": {
1248
- "@vue/devtools-api": "^6.6.3",
1249
- "vue-demi": "^0.14.10"
1327
+ "@vue/devtools-api": "^7.7.7"
1250
1328
  },
1251
1329
  "funding": {
1252
1330
  "url": "https://github.com/sponsors/posva"
1253
1331
  },
1254
1332
  "peerDependencies": {
1255
- "typescript": ">=4.4.4",
1256
- "vue": "^2.7.0 || ^3.5.11"
1333
+ "typescript": ">=4.5.0",
1334
+ "vue": "^3.5.11"
1257
1335
  },
1258
1336
  "peerDependenciesMeta": {
1259
1337
  "typescript": {
@@ -1261,6 +1339,15 @@
1261
1339
  }
1262
1340
  }
1263
1341
  },
1342
+ "node_modules/pinia/node_modules/@vue/devtools-api": {
1343
+ "version": "7.7.9",
1344
+ "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-7.7.9.tgz",
1345
+ "integrity": "sha512-kIE8wvwlcZ6TJTbNeU2HQNtaxLx3a84aotTITUuL/4bzfPxzajGBOoqjMhwZJ8L9qFYDU/lAYMEEm11dnZOD6g==",
1346
+ "license": "MIT",
1347
+ "dependencies": {
1348
+ "@vue/devtools-kit": "^7.7.9"
1349
+ }
1350
+ },
1264
1351
  "node_modules/playwright": {
1265
1352
  "version": "1.57.0",
1266
1353
  "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.57.0.tgz",
@@ -1321,6 +1408,12 @@
1321
1408
  "node": "^10 || ^12 || >=14"
1322
1409
  }
1323
1410
  },
1411
+ "node_modules/rfdc": {
1412
+ "version": "1.4.1",
1413
+ "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz",
1414
+ "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==",
1415
+ "license": "MIT"
1416
+ },
1324
1417
  "node_modules/rollup": {
1325
1418
  "version": "4.54.0",
1326
1419
  "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.54.0.tgz",
@@ -1372,6 +1465,27 @@
1372
1465
  "node": ">=0.10.0"
1373
1466
  }
1374
1467
  },
1468
+ "node_modules/speakingurl": {
1469
+ "version": "14.0.1",
1470
+ "resolved": "https://registry.npmjs.org/speakingurl/-/speakingurl-14.0.1.tgz",
1471
+ "integrity": "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==",
1472
+ "license": "BSD-3-Clause",
1473
+ "engines": {
1474
+ "node": ">=0.10.0"
1475
+ }
1476
+ },
1477
+ "node_modules/superjson": {
1478
+ "version": "2.2.6",
1479
+ "resolved": "https://registry.npmjs.org/superjson/-/superjson-2.2.6.tgz",
1480
+ "integrity": "sha512-H+ue8Zo4vJmV2nRjpx86P35lzwDT3nItnIsocgumgr0hHMQ+ZGq5vrERg9kJBo5AWGmxZDhzDo+WVIJqkB0cGA==",
1481
+ "license": "MIT",
1482
+ "dependencies": {
1483
+ "copy-anything": "^4"
1484
+ },
1485
+ "engines": {
1486
+ "node": ">=16"
1487
+ }
1488
+ },
1375
1489
  "node_modules/tinyglobby": {
1376
1490
  "version": "0.2.15",
1377
1491
  "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
@@ -1521,32 +1635,6 @@
1521
1635
  }
1522
1636
  }
1523
1637
  },
1524
- "node_modules/vue-demi": {
1525
- "version": "0.14.10",
1526
- "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz",
1527
- "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==",
1528
- "hasInstallScript": true,
1529
- "license": "MIT",
1530
- "bin": {
1531
- "vue-demi-fix": "bin/vue-demi-fix.js",
1532
- "vue-demi-switch": "bin/vue-demi-switch.js"
1533
- },
1534
- "engines": {
1535
- "node": ">=12"
1536
- },
1537
- "funding": {
1538
- "url": "https://github.com/sponsors/antfu"
1539
- },
1540
- "peerDependencies": {
1541
- "@vue/composition-api": "^1.0.0-rc.1",
1542
- "vue": "^3.0.0-0 || ^2.6.0"
1543
- },
1544
- "peerDependenciesMeta": {
1545
- "@vue/composition-api": {
1546
- "optional": true
1547
- }
1548
- }
1549
- },
1550
1638
  "node_modules/vue-router": {
1551
1639
  "version": "4.6.4",
1552
1640
  "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.6.4.tgz",
@@ -4,7 +4,7 @@
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "scripts": {
7
- "stop": "npx kill-port 3333",
7
+ "stop": "lsof -ti :3333 2>/dev/null | xargs -r kill -9 || echo 'Port 3333 is free'",
8
8
  "dev": "npm run stop && vite",
9
9
  "build": "vue-tsc && vite build",
10
10
  "preview": "vite preview",
@@ -13,7 +13,7 @@
13
13
  },
14
14
  "dependencies": {
15
15
  "een-api-toolkit": "file:../..",
16
- "pinia": "^2.1.7",
16
+ "pinia": "^3.0.4",
17
17
  "vue": "^3.4.0",
18
18
  "vue-router": "^4.2.0"
19
19
  },
@@ -0,0 +1,142 @@
1
+ # EEN API Toolkit - Vue Cameras Example
2
+
3
+ A Vue 3 example demonstrating how to list and view EEN cameras using the een-api-toolkit.
4
+
5
+ ![Cameras Screenshot](cameras-screenshot.png)
6
+
7
+ ## Features Demonstrated
8
+
9
+ - OAuth authentication flow (login, callback, logout)
10
+ - Protected routes with navigation guards
11
+ - `getCameras()` function for listing cameras with pagination
12
+ - `getCamera()` function for fetching camera details
13
+ - Status filtering (online, streaming, offline, device offline, bridge offline, error)
14
+ - Camera card grid with status badges
15
+ - Detailed camera view with device info
16
+
17
+ ## APIs Used
18
+
19
+ - `getCameras()` - List cameras with filtering and pagination
20
+ - `getCamera()` - Get single camera by ID
21
+ - `useAuthStore()` - Authentication state management
22
+ - `initEenToolkit()` - Toolkit initialization
23
+
24
+ ## Setup
25
+
26
+ ### Prerequisites
27
+
28
+ 1. **Start the OAuth proxy** (required for authentication):
29
+
30
+ The OAuth proxy is a separate project that handles token management securely.
31
+ Clone and run it from: https://github.com/klaushofrichter/een-oauth-proxy
32
+
33
+ ```bash
34
+ # In a separate terminal, from the een-oauth-proxy directory
35
+ npm install
36
+ npm run dev
37
+ ```
38
+
39
+ The proxy should be running at `http://localhost:8787`.
40
+
41
+ ### Example Setup
42
+
43
+ All commands below should be run from this example directory (`examples/vue-cameras/`):
44
+
45
+ 2. Copy the environment file:
46
+ ```bash
47
+ # From examples/vue-cameras/
48
+ cp .env.example .env
49
+ ```
50
+
51
+ 3. Edit `.env` with your EEN credentials:
52
+ ```env
53
+ VITE_EEN_CLIENT_ID=your-client-id
54
+ VITE_PROXY_URL=http://localhost:8787
55
+ # DO NOT change the redirect URI - EEN IDP only permits this URL
56
+ VITE_REDIRECT_URI=http://127.0.0.1:3333
57
+ ```
58
+
59
+ 4. Install dependencies and start:
60
+ ```bash
61
+ # From examples/vue-cameras/
62
+ npm install
63
+ npm run dev
64
+ ```
65
+
66
+ 5. Open http://127.0.0.1:3333 in your browser.
67
+
68
+ **Important:** The EEN Identity Provider only permits `http://127.0.0.1:3333` as the OAuth redirect URI. Do not use `localhost` or other ports.
69
+
70
+ **Note:** Development and testing was done on macOS. The `npm run stop` command uses `lsof`, which is not available on Windows. Windows users should manually stop any process on port 3333 or use `npx kill-port 3333` instead.
71
+
72
+ ## Project Structure
73
+
74
+ ```
75
+ src/
76
+ ├── main.ts # App entry, toolkit initialization
77
+ ├── App.vue # Root component with navigation
78
+ ├── router/
79
+ │ └── index.ts # Vue Router with auth guards
80
+ └── views/
81
+ ├── Home.vue # Home page with login prompt
82
+ ├── Login.vue # OAuth login redirect
83
+ ├── Callback.vue # OAuth callback handler
84
+ ├── Cameras.vue # Camera list with filtering
85
+ ├── CameraDetail.vue # Single camera details
86
+ └── Logout.vue # Logout handler
87
+ ```
88
+
89
+ ## Key Code Examples
90
+
91
+ ### Listing Cameras with Filtering (Cameras.vue)
92
+
93
+ ```typescript
94
+ import { getCameras, type Camera, type ListCamerasParams } from 'een-api-toolkit'
95
+
96
+ const params = ref<ListCamerasParams>({
97
+ pageSize: 20,
98
+ include: ['deviceInfo', 'status']
99
+ })
100
+
101
+ async function fetchCameras() {
102
+ const result = await getCameras(params.value)
103
+ if (result.error) {
104
+ error.value = result.error
105
+ } else {
106
+ cameras.value = result.data.results
107
+ nextPageToken.value = result.data.nextPageToken
108
+ }
109
+ }
110
+ ```
111
+
112
+ ### Fetching Camera Details (CameraDetail.vue)
113
+
114
+ ```typescript
115
+ import { getCamera } from 'een-api-toolkit'
116
+
117
+ const result = await getCamera(cameraId, {
118
+ include: ['deviceInfo', 'status']
119
+ })
120
+
121
+ if (result.error) {
122
+ error.value = result.error
123
+ } else {
124
+ camera.value = result.data
125
+ }
126
+ ```
127
+
128
+ ### Status Filtering
129
+
130
+ ```typescript
131
+ // Watch for status filter changes
132
+ watch(statusFilter, async (newStatus) => {
133
+ if (newStatus) {
134
+ setParams({
135
+ pageSize: 20,
136
+ include: ['deviceInfo', 'status'],
137
+ status__in: [newStatus]
138
+ })
139
+ }
140
+ await fetchCameras()
141
+ })
142
+ ```