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 +45 -8
- package/README.md +38 -0
- package/docs/AI-CONTEXT.md +1 -1
- package/examples/vue-bridges/README.md +126 -0
- package/examples/vue-bridges/bridges-screenshot.png +0 -0
- package/examples/vue-bridges/package-lock.json +130 -42
- package/examples/vue-bridges/package.json +2 -2
- package/examples/vue-cameras/README.md +142 -0
- package/examples/vue-cameras/cameras-screenshot.png +0 -0
- package/examples/vue-cameras/package-lock.json +130 -42
- package/examples/vue-cameras/package.json +2 -2
- package/examples/vue-feeds/README.md +162 -0
- package/examples/vue-feeds/e2e/auth.spec.ts +182 -444
- package/examples/vue-feeds/feeds-screenshot.png +0 -0
- package/examples/vue-feeds/package-lock.json +130 -42
- package/examples/vue-feeds/package.json +2 -2
- package/examples/vue-feeds/playwright.config.ts +28 -7
- package/examples/vue-media/README.md +187 -0
- package/examples/vue-media/e2e/auth.spec.ts +218 -298
- package/examples/vue-media/media-screenshot.png +0 -0
- package/examples/vue-media/package-lock.json +130 -42
- package/examples/vue-media/package.json +2 -2
- package/examples/vue-media/playwright.config.ts +28 -7
- package/examples/vue-users/README.md +58 -15
- package/examples/vue-users/package-lock.json +132 -44
- package/examples/vue-users/package.json +3 -3
- package/examples/vue-users/users-screenshot.png +0 -0
- package/package.json +12 -11
|
Binary file
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"@een/live-video-web-sdk": "^1.10.2",
|
|
12
12
|
"een-api-toolkit": "file:../..",
|
|
13
|
-
"pinia": "^
|
|
13
|
+
"pinia": "^3.0.4",
|
|
14
14
|
"vue": "^3.4.0",
|
|
15
15
|
"vue-router": "^4.2.0"
|
|
16
16
|
},
|
|
@@ -24,21 +24,22 @@
|
|
|
24
24
|
}
|
|
25
25
|
},
|
|
26
26
|
"../..": {
|
|
27
|
-
"version": "0.1.
|
|
27
|
+
"version": "0.1.13",
|
|
28
28
|
"license": "MIT",
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"@playwright/test": "^1.57.0",
|
|
31
|
-
"@types/node": "^
|
|
32
|
-
"@typescript-eslint/eslint-plugin": "^
|
|
33
|
-
"@typescript-eslint/parser": "^
|
|
31
|
+
"@types/node": "^25.0.3",
|
|
32
|
+
"@typescript-eslint/eslint-plugin": "^8.51.0",
|
|
33
|
+
"@typescript-eslint/parser": "^8.51.0",
|
|
34
34
|
"@vitejs/plugin-vue": "^6.0.0",
|
|
35
|
-
"@vue/tsconfig": "^0.
|
|
35
|
+
"@vue/tsconfig": "^0.8.1",
|
|
36
36
|
"dotenv": "^17.2.3",
|
|
37
|
-
"eslint": "^
|
|
38
|
-
"eslint-plugin-vue": "^
|
|
37
|
+
"eslint": "^9.39.2",
|
|
38
|
+
"eslint-plugin-vue": "^10.6.2",
|
|
39
|
+
"globals": "^17.0.0",
|
|
39
40
|
"husky": "^9.1.7",
|
|
40
41
|
"jsdom": "^27.4.0",
|
|
41
|
-
"pinia": "^
|
|
42
|
+
"pinia": "^3.0.4",
|
|
42
43
|
"tsx": "^4.21.0",
|
|
43
44
|
"typedoc": "^0.28.15",
|
|
44
45
|
"typedoc-plugin-markdown": "^4.9.0",
|
|
@@ -997,6 +998,30 @@
|
|
|
997
998
|
"integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==",
|
|
998
999
|
"license": "MIT"
|
|
999
1000
|
},
|
|
1001
|
+
"node_modules/@vue/devtools-kit": {
|
|
1002
|
+
"version": "7.7.9",
|
|
1003
|
+
"resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.7.9.tgz",
|
|
1004
|
+
"integrity": "sha512-PyQ6odHSgiDVd4hnTP+aDk2X4gl2HmLDfiyEnn3/oV+ckFDuswRs4IbBT7vacMuGdwY/XemxBoh302ctbsptuA==",
|
|
1005
|
+
"license": "MIT",
|
|
1006
|
+
"dependencies": {
|
|
1007
|
+
"@vue/devtools-shared": "^7.7.9",
|
|
1008
|
+
"birpc": "^2.3.0",
|
|
1009
|
+
"hookable": "^5.5.3",
|
|
1010
|
+
"mitt": "^3.0.1",
|
|
1011
|
+
"perfect-debounce": "^1.0.0",
|
|
1012
|
+
"speakingurl": "^14.0.1",
|
|
1013
|
+
"superjson": "^2.2.2"
|
|
1014
|
+
}
|
|
1015
|
+
},
|
|
1016
|
+
"node_modules/@vue/devtools-shared": {
|
|
1017
|
+
"version": "7.7.9",
|
|
1018
|
+
"resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.7.9.tgz",
|
|
1019
|
+
"integrity": "sha512-iWAb0v2WYf0QWmxCGy0seZNDPdO3Sp5+u78ORnyeonS6MT4PC7VPrryX2BpMJrwlDeaZ6BD4vP4XKjK0SZqaeA==",
|
|
1020
|
+
"license": "MIT",
|
|
1021
|
+
"dependencies": {
|
|
1022
|
+
"rfdc": "^1.4.1"
|
|
1023
|
+
}
|
|
1024
|
+
},
|
|
1000
1025
|
"node_modules/@vue/language-core": {
|
|
1001
1026
|
"version": "3.2.1",
|
|
1002
1027
|
"resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-3.2.1.tgz",
|
|
@@ -1070,6 +1095,30 @@
|
|
|
1070
1095
|
"dev": true,
|
|
1071
1096
|
"license": "MIT"
|
|
1072
1097
|
},
|
|
1098
|
+
"node_modules/birpc": {
|
|
1099
|
+
"version": "2.9.0",
|
|
1100
|
+
"resolved": "https://registry.npmjs.org/birpc/-/birpc-2.9.0.tgz",
|
|
1101
|
+
"integrity": "sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==",
|
|
1102
|
+
"license": "MIT",
|
|
1103
|
+
"funding": {
|
|
1104
|
+
"url": "https://github.com/sponsors/antfu"
|
|
1105
|
+
}
|
|
1106
|
+
},
|
|
1107
|
+
"node_modules/copy-anything": {
|
|
1108
|
+
"version": "4.0.5",
|
|
1109
|
+
"resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-4.0.5.tgz",
|
|
1110
|
+
"integrity": "sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA==",
|
|
1111
|
+
"license": "MIT",
|
|
1112
|
+
"dependencies": {
|
|
1113
|
+
"is-what": "^5.2.0"
|
|
1114
|
+
},
|
|
1115
|
+
"engines": {
|
|
1116
|
+
"node": ">=18"
|
|
1117
|
+
},
|
|
1118
|
+
"funding": {
|
|
1119
|
+
"url": "https://github.com/sponsors/mesqueeb"
|
|
1120
|
+
}
|
|
1121
|
+
},
|
|
1073
1122
|
"node_modules/csstype": {
|
|
1074
1123
|
"version": "3.2.3",
|
|
1075
1124
|
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
|
|
@@ -1186,6 +1235,24 @@
|
|
|
1186
1235
|
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
|
1187
1236
|
}
|
|
1188
1237
|
},
|
|
1238
|
+
"node_modules/hookable": {
|
|
1239
|
+
"version": "5.5.3",
|
|
1240
|
+
"resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz",
|
|
1241
|
+
"integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==",
|
|
1242
|
+
"license": "MIT"
|
|
1243
|
+
},
|
|
1244
|
+
"node_modules/is-what": {
|
|
1245
|
+
"version": "5.5.0",
|
|
1246
|
+
"resolved": "https://registry.npmjs.org/is-what/-/is-what-5.5.0.tgz",
|
|
1247
|
+
"integrity": "sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw==",
|
|
1248
|
+
"license": "MIT",
|
|
1249
|
+
"engines": {
|
|
1250
|
+
"node": ">=18"
|
|
1251
|
+
},
|
|
1252
|
+
"funding": {
|
|
1253
|
+
"url": "https://github.com/sponsors/mesqueeb"
|
|
1254
|
+
}
|
|
1255
|
+
},
|
|
1189
1256
|
"node_modules/magic-string": {
|
|
1190
1257
|
"version": "0.30.21",
|
|
1191
1258
|
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
|
|
@@ -1195,6 +1262,12 @@
|
|
|
1195
1262
|
"@jridgewell/sourcemap-codec": "^1.5.5"
|
|
1196
1263
|
}
|
|
1197
1264
|
},
|
|
1265
|
+
"node_modules/mitt": {
|
|
1266
|
+
"version": "3.0.1",
|
|
1267
|
+
"resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz",
|
|
1268
|
+
"integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==",
|
|
1269
|
+
"license": "MIT"
|
|
1270
|
+
},
|
|
1198
1271
|
"node_modules/muggle-string": {
|
|
1199
1272
|
"version": "0.4.1",
|
|
1200
1273
|
"resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.4.1.tgz",
|
|
@@ -1227,6 +1300,12 @@
|
|
|
1227
1300
|
"dev": true,
|
|
1228
1301
|
"license": "MIT"
|
|
1229
1302
|
},
|
|
1303
|
+
"node_modules/perfect-debounce": {
|
|
1304
|
+
"version": "1.0.0",
|
|
1305
|
+
"resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz",
|
|
1306
|
+
"integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==",
|
|
1307
|
+
"license": "MIT"
|
|
1308
|
+
},
|
|
1230
1309
|
"node_modules/picocolors": {
|
|
1231
1310
|
"version": "1.1.1",
|
|
1232
1311
|
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
|
@@ -1247,20 +1326,19 @@
|
|
|
1247
1326
|
}
|
|
1248
1327
|
},
|
|
1249
1328
|
"node_modules/pinia": {
|
|
1250
|
-
"version": "
|
|
1251
|
-
"resolved": "https://registry.npmjs.org/pinia/-/pinia-
|
|
1252
|
-
"integrity": "sha512-
|
|
1329
|
+
"version": "3.0.4",
|
|
1330
|
+
"resolved": "https://registry.npmjs.org/pinia/-/pinia-3.0.4.tgz",
|
|
1331
|
+
"integrity": "sha512-l7pqLUFTI/+ESXn6k3nu30ZIzW5E2WZF/LaHJEpoq6ElcLD+wduZoB2kBN19du6K/4FDpPMazY2wJr+IndBtQw==",
|
|
1253
1332
|
"license": "MIT",
|
|
1254
1333
|
"dependencies": {
|
|
1255
|
-
"@vue/devtools-api": "^
|
|
1256
|
-
"vue-demi": "^0.14.10"
|
|
1334
|
+
"@vue/devtools-api": "^7.7.7"
|
|
1257
1335
|
},
|
|
1258
1336
|
"funding": {
|
|
1259
1337
|
"url": "https://github.com/sponsors/posva"
|
|
1260
1338
|
},
|
|
1261
1339
|
"peerDependencies": {
|
|
1262
|
-
"typescript": ">=4.
|
|
1263
|
-
"vue": "^
|
|
1340
|
+
"typescript": ">=4.5.0",
|
|
1341
|
+
"vue": "^3.5.11"
|
|
1264
1342
|
},
|
|
1265
1343
|
"peerDependenciesMeta": {
|
|
1266
1344
|
"typescript": {
|
|
@@ -1268,6 +1346,15 @@
|
|
|
1268
1346
|
}
|
|
1269
1347
|
}
|
|
1270
1348
|
},
|
|
1349
|
+
"node_modules/pinia/node_modules/@vue/devtools-api": {
|
|
1350
|
+
"version": "7.7.9",
|
|
1351
|
+
"resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-7.7.9.tgz",
|
|
1352
|
+
"integrity": "sha512-kIE8wvwlcZ6TJTbNeU2HQNtaxLx3a84aotTITUuL/4bzfPxzajGBOoqjMhwZJ8L9qFYDU/lAYMEEm11dnZOD6g==",
|
|
1353
|
+
"license": "MIT",
|
|
1354
|
+
"dependencies": {
|
|
1355
|
+
"@vue/devtools-kit": "^7.7.9"
|
|
1356
|
+
}
|
|
1357
|
+
},
|
|
1271
1358
|
"node_modules/playwright": {
|
|
1272
1359
|
"version": "1.57.0",
|
|
1273
1360
|
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.57.0.tgz",
|
|
@@ -1328,6 +1415,12 @@
|
|
|
1328
1415
|
"node": "^10 || ^12 || >=14"
|
|
1329
1416
|
}
|
|
1330
1417
|
},
|
|
1418
|
+
"node_modules/rfdc": {
|
|
1419
|
+
"version": "1.4.1",
|
|
1420
|
+
"resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz",
|
|
1421
|
+
"integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==",
|
|
1422
|
+
"license": "MIT"
|
|
1423
|
+
},
|
|
1331
1424
|
"node_modules/rollup": {
|
|
1332
1425
|
"version": "4.54.0",
|
|
1333
1426
|
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.54.0.tgz",
|
|
@@ -1379,6 +1472,27 @@
|
|
|
1379
1472
|
"node": ">=0.10.0"
|
|
1380
1473
|
}
|
|
1381
1474
|
},
|
|
1475
|
+
"node_modules/speakingurl": {
|
|
1476
|
+
"version": "14.0.1",
|
|
1477
|
+
"resolved": "https://registry.npmjs.org/speakingurl/-/speakingurl-14.0.1.tgz",
|
|
1478
|
+
"integrity": "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==",
|
|
1479
|
+
"license": "BSD-3-Clause",
|
|
1480
|
+
"engines": {
|
|
1481
|
+
"node": ">=0.10.0"
|
|
1482
|
+
}
|
|
1483
|
+
},
|
|
1484
|
+
"node_modules/superjson": {
|
|
1485
|
+
"version": "2.2.6",
|
|
1486
|
+
"resolved": "https://registry.npmjs.org/superjson/-/superjson-2.2.6.tgz",
|
|
1487
|
+
"integrity": "sha512-H+ue8Zo4vJmV2nRjpx86P35lzwDT3nItnIsocgumgr0hHMQ+ZGq5vrERg9kJBo5AWGmxZDhzDo+WVIJqkB0cGA==",
|
|
1488
|
+
"license": "MIT",
|
|
1489
|
+
"dependencies": {
|
|
1490
|
+
"copy-anything": "^4"
|
|
1491
|
+
},
|
|
1492
|
+
"engines": {
|
|
1493
|
+
"node": ">=16"
|
|
1494
|
+
}
|
|
1495
|
+
},
|
|
1382
1496
|
"node_modules/tinyglobby": {
|
|
1383
1497
|
"version": "0.2.15",
|
|
1384
1498
|
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
|
|
@@ -1528,32 +1642,6 @@
|
|
|
1528
1642
|
}
|
|
1529
1643
|
}
|
|
1530
1644
|
},
|
|
1531
|
-
"node_modules/vue-demi": {
|
|
1532
|
-
"version": "0.14.10",
|
|
1533
|
-
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz",
|
|
1534
|
-
"integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==",
|
|
1535
|
-
"hasInstallScript": true,
|
|
1536
|
-
"license": "MIT",
|
|
1537
|
-
"bin": {
|
|
1538
|
-
"vue-demi-fix": "bin/vue-demi-fix.js",
|
|
1539
|
-
"vue-demi-switch": "bin/vue-demi-switch.js"
|
|
1540
|
-
},
|
|
1541
|
-
"engines": {
|
|
1542
|
-
"node": ">=12"
|
|
1543
|
-
},
|
|
1544
|
-
"funding": {
|
|
1545
|
-
"url": "https://github.com/sponsors/antfu"
|
|
1546
|
-
},
|
|
1547
|
-
"peerDependencies": {
|
|
1548
|
-
"@vue/composition-api": "^1.0.0-rc.1",
|
|
1549
|
-
"vue": "^3.0.0-0 || ^2.6.0"
|
|
1550
|
-
},
|
|
1551
|
-
"peerDependenciesMeta": {
|
|
1552
|
-
"@vue/composition-api": {
|
|
1553
|
-
"optional": true
|
|
1554
|
-
}
|
|
1555
|
-
}
|
|
1556
|
-
},
|
|
1557
1645
|
"node_modules/vue-router": {
|
|
1558
1646
|
"version": "4.6.4",
|
|
1559
1647
|
"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": "
|
|
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",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"dependencies": {
|
|
15
15
|
"@een/live-video-web-sdk": "^1.10.2",
|
|
16
16
|
"een-api-toolkit": "file:../..",
|
|
17
|
-
"pinia": "^
|
|
17
|
+
"pinia": "^3.0.4",
|
|
18
18
|
"vue": "^3.4.0",
|
|
19
19
|
"vue-router": "^4.2.0"
|
|
20
20
|
},
|
|
@@ -1,18 +1,39 @@
|
|
|
1
1
|
import { defineConfig, devices } from '@playwright/test'
|
|
2
|
+
import dotenv from 'dotenv'
|
|
3
|
+
import path from 'path'
|
|
4
|
+
import { fileURLToPath } from 'url'
|
|
5
|
+
|
|
6
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
7
|
+
|
|
8
|
+
// Load .env files: parent .env first, then local .env overrides parent values
|
|
9
|
+
dotenv.config({ path: path.resolve(__dirname, '../../.env') })
|
|
10
|
+
dotenv.config({ path: path.resolve(__dirname, '.env'), override: true })
|
|
11
|
+
|
|
12
|
+
const redirectUri = process.env.VITE_REDIRECT_URI || 'http://127.0.0.1:3333'
|
|
13
|
+
if (!redirectUri.startsWith('http://127.0.0.1:') && !redirectUri.startsWith('http://localhost:')) {
|
|
14
|
+
throw new Error('VITE_REDIRECT_URI must use localhost or 127.0.0.1 for security')
|
|
15
|
+
}
|
|
16
|
+
const baseURL = redirectUri
|
|
17
|
+
|
|
18
|
+
// Export for use in test files
|
|
19
|
+
export { baseURL }
|
|
2
20
|
|
|
3
21
|
export default defineConfig({
|
|
4
22
|
testDir: './e2e',
|
|
23
|
+
testMatch: '**/*.spec.ts',
|
|
5
24
|
fullyParallel: false,
|
|
6
25
|
forbidOnly: !!process.env.CI,
|
|
7
|
-
retries:
|
|
26
|
+
retries: 0,
|
|
27
|
+
maxFailures: 1,
|
|
8
28
|
workers: 1,
|
|
9
|
-
reporter: 'html',
|
|
10
|
-
timeout:
|
|
29
|
+
reporter: [['html', { open: 'never' }]],
|
|
30
|
+
timeout: 30000,
|
|
11
31
|
use: {
|
|
12
|
-
baseURL
|
|
32
|
+
baseURL,
|
|
13
33
|
trace: 'on-first-retry',
|
|
14
|
-
|
|
34
|
+
video: 'retain-on-failure'
|
|
15
35
|
},
|
|
36
|
+
outputDir: './e2e-results/',
|
|
16
37
|
projects: [
|
|
17
38
|
{
|
|
18
39
|
name: 'chromium',
|
|
@@ -21,8 +42,8 @@ export default defineConfig({
|
|
|
21
42
|
],
|
|
22
43
|
webServer: {
|
|
23
44
|
command: 'npm run dev',
|
|
24
|
-
url:
|
|
45
|
+
url: baseURL,
|
|
25
46
|
reuseExistingServer: !process.env.CI,
|
|
26
|
-
timeout:
|
|
47
|
+
timeout: 30000
|
|
27
48
|
}
|
|
28
49
|
})
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# EEN API Toolkit - Vue Media Example
|
|
2
|
+
|
|
3
|
+
A Vue 3 example demonstrating how to fetch live and recorded images from EEN cameras using the een-api-toolkit.
|
|
4
|
+
|
|
5
|
+

|
|
6
|
+
|
|
7
|
+
## Features Demonstrated
|
|
8
|
+
|
|
9
|
+
- OAuth authentication flow (login, callback, logout)
|
|
10
|
+
- Protected routes with navigation guards
|
|
11
|
+
- `getCameras()` function for listing cameras
|
|
12
|
+
- `getLiveImage()` function for fetching live preview images
|
|
13
|
+
- `getRecordedImage()` function for fetching recorded images with navigation
|
|
14
|
+
- Camera selection with persistence across pages
|
|
15
|
+
- Auto-refresh functionality for live images
|
|
16
|
+
- Time-based navigation for recorded images (prev/next)
|
|
17
|
+
- Image timestamp display
|
|
18
|
+
|
|
19
|
+
## APIs Used
|
|
20
|
+
|
|
21
|
+
- `getCameras()` - List available cameras
|
|
22
|
+
- `getLiveImage()` - Fetch live preview image as base64
|
|
23
|
+
- `getRecordedImage()` - Fetch recorded image at specific timestamp
|
|
24
|
+
- `useAuthStore()` - Authentication state management
|
|
25
|
+
- `initEenToolkit()` - Toolkit initialization
|
|
26
|
+
|
|
27
|
+
## Setup
|
|
28
|
+
|
|
29
|
+
### Prerequisites
|
|
30
|
+
|
|
31
|
+
1. **Start the OAuth proxy** (required for authentication):
|
|
32
|
+
|
|
33
|
+
The OAuth proxy is a separate project that handles token management securely.
|
|
34
|
+
Clone and run it from: https://github.com/klaushofrichter/een-oauth-proxy
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
# In a separate terminal, from the een-oauth-proxy directory
|
|
38
|
+
npm install
|
|
39
|
+
npm run dev
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
The proxy should be running at `http://localhost:8787`.
|
|
43
|
+
|
|
44
|
+
### Example Setup
|
|
45
|
+
|
|
46
|
+
All commands below should be run from this example directory (`examples/vue-media/`):
|
|
47
|
+
|
|
48
|
+
2. Copy the environment file:
|
|
49
|
+
```bash
|
|
50
|
+
# From examples/vue-media/
|
|
51
|
+
cp .env.example .env
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
3. Edit `.env` with your EEN credentials:
|
|
55
|
+
```env
|
|
56
|
+
VITE_EEN_CLIENT_ID=your-client-id
|
|
57
|
+
VITE_PROXY_URL=http://localhost:8787
|
|
58
|
+
# DO NOT change the redirect URI - EEN IDP only permits this URL
|
|
59
|
+
VITE_REDIRECT_URI=http://127.0.0.1:3333
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
4. Install dependencies and start:
|
|
63
|
+
```bash
|
|
64
|
+
# From examples/vue-media/
|
|
65
|
+
npm install
|
|
66
|
+
npm run dev
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
5. Open http://127.0.0.1:3333 in your browser.
|
|
70
|
+
|
|
71
|
+
**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.
|
|
72
|
+
|
|
73
|
+
**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.
|
|
74
|
+
|
|
75
|
+
## Project Structure
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
src/
|
|
79
|
+
├── main.ts # App entry, toolkit initialization
|
|
80
|
+
├── App.vue # Root component with navigation
|
|
81
|
+
├── router/
|
|
82
|
+
│ └── index.ts # Vue Router with auth guards
|
|
83
|
+
└── views/
|
|
84
|
+
├── Home.vue # Home page with login prompt
|
|
85
|
+
├── Login.vue # OAuth login redirect
|
|
86
|
+
├── Callback.vue # OAuth callback handler
|
|
87
|
+
├── LiveCamera.vue # Live image viewer with auto-refresh
|
|
88
|
+
├── RecordedImage.vue # Recorded image viewer with navigation
|
|
89
|
+
└── Logout.vue # Logout handler
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Key Code Examples
|
|
93
|
+
|
|
94
|
+
### Fetching Live Images (LiveCamera.vue)
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
import { getLiveImage, type LiveImageParams } from 'een-api-toolkit'
|
|
98
|
+
|
|
99
|
+
async function fetchLiveImage() {
|
|
100
|
+
const result = await getLiveImage(selectedCameraId.value, {
|
|
101
|
+
type: 'preview'
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
if (result.error) {
|
|
105
|
+
error.value = result.error.message
|
|
106
|
+
} else {
|
|
107
|
+
imageData.value = result.data.image
|
|
108
|
+
timestamp.value = result.data.timestamp
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Auto-Refresh for Live Images
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
let refreshInterval: number | null = null
|
|
117
|
+
|
|
118
|
+
function startAutoRefresh() {
|
|
119
|
+
refreshInterval = window.setInterval(() => {
|
|
120
|
+
fetchLiveImage()
|
|
121
|
+
}, 2000) // Refresh every 2 seconds
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function stopAutoRefresh() {
|
|
125
|
+
if (refreshInterval) {
|
|
126
|
+
clearInterval(refreshInterval)
|
|
127
|
+
refreshInterval = null
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Fetching Recorded Images (RecordedImage.vue)
|
|
133
|
+
|
|
134
|
+
```typescript
|
|
135
|
+
import { getRecordedImage, type RecordedImageParams } from 'een-api-toolkit'
|
|
136
|
+
|
|
137
|
+
async function fetchRecordedImage() {
|
|
138
|
+
const result = await getRecordedImage(selectedCameraId.value, {
|
|
139
|
+
timestamp__gte: selectedTimestamp.value,
|
|
140
|
+
type: 'preview'
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
if (result.error) {
|
|
144
|
+
error.value = result.error.message
|
|
145
|
+
} else {
|
|
146
|
+
imageData.value = result.data.image
|
|
147
|
+
actualTimestamp.value = result.data.timestamp
|
|
148
|
+
prevToken.value = result.data.prevToken
|
|
149
|
+
nextToken.value = result.data.nextToken
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Navigating Recorded Images
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
async function navigateNext() {
|
|
158
|
+
if (!nextToken.value) return
|
|
159
|
+
|
|
160
|
+
const result = await getRecordedImage(selectedCameraId.value, {
|
|
161
|
+
next: nextToken.value,
|
|
162
|
+
type: 'preview'
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
if (!result.error) {
|
|
166
|
+
imageData.value = result.data.image
|
|
167
|
+
actualTimestamp.value = result.data.timestamp
|
|
168
|
+
prevToken.value = result.data.prevToken
|
|
169
|
+
nextToken.value = result.data.nextToken
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### Displaying Images
|
|
175
|
+
|
|
176
|
+
```vue
|
|
177
|
+
<template>
|
|
178
|
+
<img
|
|
179
|
+
v-if="imageData"
|
|
180
|
+
:src="`data:image/jpeg;base64,${imageData}`"
|
|
181
|
+
alt="Camera image"
|
|
182
|
+
/>
|
|
183
|
+
<p v-if="timestamp">
|
|
184
|
+
Timestamp: {{ new Date(timestamp).toLocaleString() }}
|
|
185
|
+
</p>
|
|
186
|
+
</template>
|
|
187
|
+
```
|