een-api-toolkit 0.1.2 → 0.1.7

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 (47) hide show
  1. package/CHANGELOG.md +10 -53
  2. package/dist/index.cjs +1 -1
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.ts +686 -1
  5. package/dist/index.js +457 -222
  6. package/dist/index.js.map +1 -1
  7. package/docs/AI-CONTEXT.md +293 -1
  8. package/examples/vue-bridges/.env.example +13 -0
  9. package/examples/vue-bridges/e2e/app.spec.ts +73 -0
  10. package/examples/vue-bridges/e2e/auth.spec.ts +206 -0
  11. package/examples/vue-bridges/index.html +13 -0
  12. package/examples/vue-bridges/package-lock.json +1583 -0
  13. package/examples/vue-bridges/package.json +28 -0
  14. package/examples/vue-bridges/playwright.config.ts +46 -0
  15. package/examples/vue-bridges/src/App.vue +108 -0
  16. package/examples/vue-bridges/src/main.ts +23 -0
  17. package/examples/vue-bridges/src/router/index.ts +68 -0
  18. package/examples/vue-bridges/src/views/BridgeDetail.vue +279 -0
  19. package/examples/vue-bridges/src/views/Bridges.vue +297 -0
  20. package/examples/vue-bridges/src/views/Callback.vue +76 -0
  21. package/examples/vue-bridges/src/views/Home.vue +150 -0
  22. package/examples/vue-bridges/src/views/Login.vue +33 -0
  23. package/examples/vue-bridges/src/views/Logout.vue +66 -0
  24. package/examples/vue-bridges/src/vite-env.d.ts +12 -0
  25. package/examples/vue-bridges/tsconfig.json +21 -0
  26. package/examples/vue-bridges/tsconfig.node.json +10 -0
  27. package/examples/vue-bridges/vite.config.ts +12 -0
  28. package/examples/vue-media/.env.example +5 -0
  29. package/examples/vue-media/e2e/app.spec.ts +55 -0
  30. package/examples/vue-media/e2e/auth.spec.ts +344 -0
  31. package/examples/vue-media/index.html +13 -0
  32. package/examples/vue-media/package-lock.json +1583 -0
  33. package/examples/vue-media/package.json +28 -0
  34. package/examples/vue-media/playwright.config.ts +28 -0
  35. package/examples/vue-media/src/App.vue +122 -0
  36. package/examples/vue-media/src/main.ts +22 -0
  37. package/examples/vue-media/src/router/index.ts +61 -0
  38. package/examples/vue-media/src/views/Callback.vue +76 -0
  39. package/examples/vue-media/src/views/Home.vue +86 -0
  40. package/examples/vue-media/src/views/LiveCamera.vue +330 -0
  41. package/examples/vue-media/src/views/Login.vue +32 -0
  42. package/examples/vue-media/src/views/Logout.vue +59 -0
  43. package/examples/vue-media/src/vite-env.d.ts +12 -0
  44. package/examples/vue-media/tsconfig.json +21 -0
  45. package/examples/vue-media/tsconfig.node.json +10 -0
  46. package/examples/vue-media/vite.config.ts +12 -0
  47. package/package.json +1 -1
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "een-api-toolkit-media-example",
3
+ "version": "0.0.1",
4
+ "private": true,
5
+ "type": "module",
6
+ "scripts": {
7
+ "stop": "npx kill-port 3333",
8
+ "dev": "npm run stop && vite",
9
+ "build": "vue-tsc && vite build",
10
+ "preview": "vite preview",
11
+ "test:e2e": "playwright test",
12
+ "test:e2e:ui": "playwright test --ui"
13
+ },
14
+ "dependencies": {
15
+ "een-api-toolkit": "file:../..",
16
+ "pinia": "^2.1.7",
17
+ "vue": "^3.4.0",
18
+ "vue-router": "^4.2.0"
19
+ },
20
+ "devDependencies": {
21
+ "@playwright/test": "^1.57.0",
22
+ "@vitejs/plugin-vue": "^6.0.0",
23
+ "dotenv": "^17.2.3",
24
+ "typescript": "~5.8.0",
25
+ "vite": "^7.3.0",
26
+ "vue-tsc": "^3.2.1"
27
+ }
28
+ }
@@ -0,0 +1,28 @@
1
+ import { defineConfig, devices } from '@playwright/test'
2
+
3
+ export default defineConfig({
4
+ testDir: './e2e',
5
+ fullyParallel: false,
6
+ forbidOnly: !!process.env.CI,
7
+ retries: process.env.CI ? 2 : 0,
8
+ workers: 1,
9
+ reporter: 'html',
10
+ timeout: 60000,
11
+ use: {
12
+ baseURL: 'http://127.0.0.1:3333',
13
+ trace: 'on-first-retry',
14
+ screenshot: 'only-on-failure'
15
+ },
16
+ projects: [
17
+ {
18
+ name: 'chromium',
19
+ use: { ...devices['Desktop Chrome'] }
20
+ }
21
+ ],
22
+ webServer: {
23
+ command: 'npm run dev',
24
+ url: 'http://127.0.0.1:3333',
25
+ reuseExistingServer: !process.env.CI,
26
+ timeout: 120000
27
+ }
28
+ })
@@ -0,0 +1,122 @@
1
+ <script setup lang="ts">
2
+ import { useAuthStore } from 'een-api-toolkit'
3
+
4
+ const authStore = useAuthStore()
5
+ </script>
6
+
7
+ <template>
8
+ <div id="app">
9
+ <header>
10
+ <h1>EEN Media Example</h1>
11
+ <nav>
12
+ <router-link to="/" data-testid="nav-home">Home</router-link>
13
+ <router-link v-if="!authStore.isAuthenticated" to="/login" data-testid="nav-login">Login</router-link>
14
+ <router-link v-if="authStore.isAuthenticated" to="/live" data-testid="nav-live">Live Camera</router-link>
15
+ <router-link v-if="authStore.isAuthenticated" to="/logout" data-testid="nav-logout">Logout</router-link>
16
+ </nav>
17
+ </header>
18
+ <main>
19
+ <router-view />
20
+ </main>
21
+ </div>
22
+ </template>
23
+
24
+ <style>
25
+ * {
26
+ box-sizing: border-box;
27
+ margin: 0;
28
+ padding: 0;
29
+ }
30
+
31
+ body {
32
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
33
+ line-height: 1.6;
34
+ color: #333;
35
+ background: #f5f5f5;
36
+ }
37
+
38
+ #app {
39
+ max-width: 1200px;
40
+ margin: 0 auto;
41
+ padding: 20px;
42
+ }
43
+
44
+ header {
45
+ background: #2c3e50;
46
+ color: white;
47
+ padding: 20px;
48
+ border-radius: 8px;
49
+ margin-bottom: 20px;
50
+ }
51
+
52
+ header h1 {
53
+ margin-bottom: 15px;
54
+ }
55
+
56
+ nav {
57
+ display: flex;
58
+ gap: 15px;
59
+ }
60
+
61
+ nav a {
62
+ color: white;
63
+ text-decoration: none;
64
+ padding: 8px 16px;
65
+ border-radius: 4px;
66
+ transition: background-color 0.2s;
67
+ }
68
+
69
+ nav a:hover {
70
+ background: rgba(255, 255, 255, 0.1);
71
+ }
72
+
73
+ nav a.router-link-active {
74
+ background: rgba(255, 255, 255, 0.2);
75
+ }
76
+
77
+ main {
78
+ background: white;
79
+ padding: 30px;
80
+ border-radius: 8px;
81
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
82
+ }
83
+
84
+ h2 {
85
+ color: #2c3e50;
86
+ margin-bottom: 20px;
87
+ }
88
+
89
+ button {
90
+ background: #3498db;
91
+ color: white;
92
+ border: none;
93
+ padding: 10px 20px;
94
+ border-radius: 4px;
95
+ cursor: pointer;
96
+ font-size: 1rem;
97
+ transition: background-color 0.2s;
98
+ }
99
+
100
+ button:hover {
101
+ background: #2980b9;
102
+ }
103
+
104
+ button:disabled {
105
+ background: #bdc3c7;
106
+ cursor: not-allowed;
107
+ }
108
+
109
+ .loading {
110
+ text-align: center;
111
+ padding: 40px;
112
+ color: #666;
113
+ }
114
+
115
+ .error {
116
+ color: #e74c3c;
117
+ padding: 15px;
118
+ background: #fdf0ef;
119
+ border-radius: 4px;
120
+ margin-bottom: 20px;
121
+ }
122
+ </style>
@@ -0,0 +1,22 @@
1
+ import { createApp } from 'vue'
2
+ import { createPinia } from 'pinia'
3
+ import { initEenToolkit } from 'een-api-toolkit'
4
+ import App from './App.vue'
5
+ import router from './router'
6
+
7
+ const app = createApp(App)
8
+ const pinia = createPinia()
9
+
10
+ // Install Pinia FIRST (required before initEenToolkit)
11
+ app.use(pinia)
12
+ app.use(router)
13
+
14
+ // Initialize the EEN API Toolkit
15
+ initEenToolkit({
16
+ proxyUrl: import.meta.env.VITE_PROXY_URL,
17
+ clientId: import.meta.env.VITE_EEN_CLIENT_ID,
18
+ redirectUri: import.meta.env.VITE_REDIRECT_URI || 'http://127.0.0.1:3333',
19
+ debug: import.meta.env.VITE_DEBUG === 'true'
20
+ })
21
+
22
+ app.mount('#app')
@@ -0,0 +1,61 @@
1
+ import { createRouter, createWebHistory } from 'vue-router'
2
+ import { useAuthStore } from 'een-api-toolkit'
3
+ import Home from '../views/Home.vue'
4
+ import Login from '../views/Login.vue'
5
+ import Callback from '../views/Callback.vue'
6
+ import LiveCamera from '../views/LiveCamera.vue'
7
+ import Logout from '../views/Logout.vue'
8
+
9
+ const router = createRouter({
10
+ history: createWebHistory(),
11
+ routes: [
12
+ {
13
+ path: '/',
14
+ name: 'home',
15
+ component: Home,
16
+ // Handle OAuth callback on root path (EEN IDP redirects to http://127.0.0.1:3333)
17
+ beforeEnter: (to, _from, next) => {
18
+ // If URL has code and state params, it's an OAuth callback
19
+ if (to.query.code && to.query.state) {
20
+ next({ name: 'callback', query: to.query })
21
+ } else {
22
+ next()
23
+ }
24
+ }
25
+ },
26
+ {
27
+ path: '/login',
28
+ name: 'login',
29
+ component: Login
30
+ },
31
+ {
32
+ path: '/callback',
33
+ name: 'callback',
34
+ component: Callback
35
+ },
36
+ {
37
+ path: '/live',
38
+ name: 'live',
39
+ component: LiveCamera,
40
+ meta: { requiresAuth: true }
41
+ },
42
+ {
43
+ path: '/logout',
44
+ name: 'logout',
45
+ component: Logout
46
+ }
47
+ ]
48
+ })
49
+
50
+ // Navigation guard for protected routes
51
+ router.beforeEach((to, _from, next) => {
52
+ const authStore = useAuthStore()
53
+
54
+ if (to.meta.requiresAuth && !authStore.isAuthenticated) {
55
+ next({ name: 'login' })
56
+ } else {
57
+ next()
58
+ }
59
+ })
60
+
61
+ export default router
@@ -0,0 +1,76 @@
1
+ <script setup lang="ts">
2
+ import { onMounted, ref } from 'vue'
3
+ import { useRouter } from 'vue-router'
4
+ import { handleAuthCallback } from 'een-api-toolkit'
5
+
6
+ const router = useRouter()
7
+ const error = ref<string | null>(null)
8
+ const processing = ref(true)
9
+
10
+ onMounted(async () => {
11
+ const url = new URL(window.location.href)
12
+ const code = url.searchParams.get('code')
13
+ const state = url.searchParams.get('state')
14
+ const errorParam = url.searchParams.get('error')
15
+
16
+ if (errorParam) {
17
+ error.value = `OAuth error: ${errorParam}`
18
+ processing.value = false
19
+ return
20
+ }
21
+
22
+ if (!code || !state) {
23
+ error.value = 'Missing authorization code or state parameter'
24
+ processing.value = false
25
+ return
26
+ }
27
+
28
+ const result = await handleAuthCallback(code, state)
29
+
30
+ if (result.error) {
31
+ error.value = result.error.message
32
+ processing.value = false
33
+ return
34
+ }
35
+
36
+ // Success - redirect to live camera view
37
+ router.push('/live')
38
+ })
39
+ </script>
40
+
41
+ <template>
42
+ <div class="callback">
43
+ <div v-if="processing" class="loading">
44
+ <h2>Authenticating...</h2>
45
+ <p>Please wait while we complete the login process.</p>
46
+ </div>
47
+
48
+ <div v-else-if="error" class="error-state">
49
+ <h2>Authentication Failed</h2>
50
+ <p class="error">{{ error }}</p>
51
+ <router-link to="/login">
52
+ <button>Try Again</button>
53
+ </router-link>
54
+ </div>
55
+ </div>
56
+ </template>
57
+
58
+ <style scoped>
59
+ .callback {
60
+ text-align: center;
61
+ max-width: 400px;
62
+ margin: 0 auto;
63
+ }
64
+
65
+ h2 {
66
+ margin-bottom: 20px;
67
+ }
68
+
69
+ .loading p {
70
+ color: #666;
71
+ }
72
+
73
+ .error-state .error {
74
+ margin-bottom: 20px;
75
+ }
76
+ </style>
@@ -0,0 +1,86 @@
1
+ <script setup lang="ts">
2
+ import { useAuthStore } from 'een-api-toolkit'
3
+
4
+ const authStore = useAuthStore()
5
+ </script>
6
+
7
+ <template>
8
+ <div class="home">
9
+ <h2>Welcome to the EEN Media Example</h2>
10
+
11
+ <div v-if="!authStore.isAuthenticated" class="login-prompt" data-testid="not-authenticated">
12
+ <p>Please log in to view live camera images.</p>
13
+ <router-link to="/login">
14
+ <button data-testid="login-button">Login with Eagle Eye Networks</button>
15
+ </router-link>
16
+ </div>
17
+
18
+ <div v-else class="authenticated" data-testid="authenticated">
19
+ <p>You are logged in!</p>
20
+ <router-link to="/live">
21
+ <button data-testid="view-live-button">View Live Camera</button>
22
+ </router-link>
23
+ </div>
24
+
25
+ <div class="description">
26
+ <h3>About This Example</h3>
27
+ <p>
28
+ This example demonstrates using the EEN Media API to fetch live images from cameras.
29
+ It showcases the following toolkit functions:
30
+ </p>
31
+ <ul>
32
+ <li><code>getCameras()</code> - List available cameras</li>
33
+ <li><code>getLiveImage()</code> - Fetch live preview images</li>
34
+ </ul>
35
+ </div>
36
+ </div>
37
+ </template>
38
+
39
+ <style scoped>
40
+ .home {
41
+ max-width: 600px;
42
+ margin: 0 auto;
43
+ }
44
+
45
+ .login-prompt,
46
+ .authenticated {
47
+ text-align: center;
48
+ padding: 30px;
49
+ margin-bottom: 30px;
50
+ background: #f8f9fa;
51
+ border-radius: 8px;
52
+ }
53
+
54
+ .login-prompt p,
55
+ .authenticated p {
56
+ margin-bottom: 20px;
57
+ color: #666;
58
+ }
59
+
60
+ .description {
61
+ padding: 20px;
62
+ background: #f8f9fa;
63
+ border-radius: 8px;
64
+ }
65
+
66
+ .description h3 {
67
+ margin-bottom: 15px;
68
+ color: #2c3e50;
69
+ }
70
+
71
+ .description ul {
72
+ margin-top: 15px;
73
+ padding-left: 25px;
74
+ }
75
+
76
+ .description li {
77
+ margin-bottom: 8px;
78
+ }
79
+
80
+ .description code {
81
+ background: #e9ecef;
82
+ padding: 2px 6px;
83
+ border-radius: 3px;
84
+ font-family: monospace;
85
+ }
86
+ </style>