een-api-toolkit 0.0.8 → 0.0.13
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 +257 -146
- package/README.md +108 -230
- package/docs/AI-CONTEXT.md +767 -0
- package/examples/vue-basic/.env.example +12 -0
- package/examples/vue-basic/README.md +146 -0
- package/examples/vue-basic/e2e/app.spec.ts +61 -0
- package/examples/vue-basic/e2e/auth.spec.ts +260 -0
- package/examples/vue-basic/index.html +13 -0
- package/examples/vue-basic/package-lock.json +1583 -0
- package/examples/vue-basic/package.json +28 -0
- package/examples/vue-basic/playwright.config.ts +47 -0
- package/examples/vue-basic/src/App.vue +108 -0
- package/examples/vue-basic/src/main.ts +23 -0
- package/examples/vue-basic/src/router/index.ts +61 -0
- package/examples/vue-basic/src/views/Callback.vue +76 -0
- package/examples/vue-basic/src/views/Home.vue +105 -0
- package/examples/vue-basic/src/views/Login.vue +33 -0
- package/examples/vue-basic/src/views/Logout.vue +59 -0
- package/examples/vue-basic/src/views/Users.vue +106 -0
- package/examples/vue-basic/src/vite-env.d.ts +12 -0
- package/examples/vue-basic/tsconfig.json +21 -0
- package/examples/vue-basic/tsconfig.node.json +10 -0
- package/examples/vue-basic/vite.config.ts +12 -0
- package/package.json +3 -1
package/README.md
CHANGED
|
@@ -1,30 +1,56 @@
|
|
|
1
1
|
# een-api-toolkit
|
|
2
2
|
|
|
3
|
-
A TypeScript library
|
|
3
|
+
A TypeScript library for the [Eagle Eye Networks](https://een.com/) Video API v3.0, designed for Vue 3 applications.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## Purpose
|
|
6
|
+
|
|
7
|
+
This toolkit aims to **simplify and accelerate web application development** for the EEN Video Platform. By providing ready-to-use composables, type-safe APIs, and secure authentication patterns, developers can focus on building features rather than wrestling with API integration details.
|
|
8
|
+
|
|
9
|
+
The project is also designed to **enable AI-assisted software development**. With comprehensive documentation, clear code patterns, and an AI-optimized context file (`docs/AI-CONTEXT.md`), AI coding assistants can effectively help developers build, extend, and maintain applications using this toolkit.
|
|
6
10
|
|
|
7
11
|
> **Note:** Work in progress - do not use in production yet.
|
|
8
12
|
|
|
9
|
-
##
|
|
13
|
+
## Key Features
|
|
14
|
+
|
|
15
|
+
- **Vue 3 Composables** - Reactive state with `useCurrentUser()`, `useUsers()`, `useUser()`
|
|
16
|
+
- **Plain Functions** - Framework-agnostic `getCurrentUser()`, `getUsers()`, `getUser()`
|
|
17
|
+
- **Secure OAuth** - Token management via proxy (refresh tokens never exposed to client)
|
|
18
|
+
- **Type-Safe** - Full TypeScript types from OpenAPI spec
|
|
19
|
+
- **Predictable Errors** - Always returns `{data, error}`, no exceptions thrown
|
|
20
|
+
|
|
21
|
+
## OAuth Proxy Requirement
|
|
22
|
+
|
|
23
|
+
This toolkit's authentication is designed to work with [een-oauth-proxy](https://github.com/klaushofrichter/een-oauth-proxy), a secure OAuth proxy implementation that:
|
|
24
|
+
|
|
25
|
+
- Keeps refresh tokens server-side (never exposed to the browser)
|
|
26
|
+
- Handles token exchange and refresh automatically
|
|
27
|
+
- Provides session management via secure cookies
|
|
28
|
+
|
|
29
|
+
**Using a different proxy?** While other OAuth proxy implementations can be used, you may need to adapt the authentication flow. The toolkit expects specific proxy endpoints (`/proxy/getAccessToken`, `/proxy/refreshAccessToken`, `/proxy/revoke`).
|
|
30
|
+
|
|
31
|
+
## Quick Start
|
|
32
|
+
|
|
33
|
+
### 1. Install
|
|
10
34
|
|
|
11
35
|
```bash
|
|
12
36
|
npm install een-api-toolkit
|
|
13
37
|
```
|
|
14
38
|
|
|
15
|
-
|
|
39
|
+
### 2. Set Up OAuth Proxy
|
|
40
|
+
|
|
41
|
+
The toolkit requires an OAuth proxy to securely handle authentication. See [een-oauth-proxy](https://github.com/klaushofrichter/een-oauth-proxy) for a Cloudflare Worker implementation.
|
|
42
|
+
|
|
16
43
|
```bash
|
|
17
|
-
|
|
18
|
-
|
|
44
|
+
# Clone and start the proxy
|
|
45
|
+
git clone https://github.com/klaushofrichter/een-oauth-proxy.git
|
|
46
|
+
cd een-oauth-proxy/proxy
|
|
19
47
|
npm install
|
|
20
|
-
npm run
|
|
21
|
-
npm link
|
|
22
|
-
|
|
23
|
-
# In your project:
|
|
24
|
-
npm link een-api-toolkit
|
|
48
|
+
npm run dev # Runs at http://localhost:8787
|
|
25
49
|
```
|
|
26
50
|
|
|
27
|
-
|
|
51
|
+
> **Important:** Your app must run on `http://127.0.0.1:3333` (not `localhost`) and handle OAuth callbacks on the root path `/`. The EEN Identity Provider requires an exact URI match. See [Troubleshooting](./docs/USER-GUIDE.md#oauth-redirect-uri-requirements-critical) for details.
|
|
52
|
+
|
|
53
|
+
### 3. Initialize in Your App
|
|
28
54
|
|
|
29
55
|
```typescript
|
|
30
56
|
// main.ts
|
|
@@ -36,286 +62,138 @@ import App from './App.vue'
|
|
|
36
62
|
const app = createApp(App)
|
|
37
63
|
app.use(createPinia())
|
|
38
64
|
|
|
39
|
-
// Initialize toolkit with proxy URL from environment
|
|
40
65
|
initEenToolkit({
|
|
41
|
-
proxyUrl: import.meta.env.VITE_PROXY_URL
|
|
66
|
+
proxyUrl: import.meta.env.VITE_PROXY_URL, // http://localhost:8787
|
|
67
|
+
clientId: import.meta.env.VITE_EEN_CLIENT_ID
|
|
42
68
|
})
|
|
43
69
|
|
|
44
70
|
app.mount('#app')
|
|
45
71
|
```
|
|
46
72
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
The toolkit uses OAuth via a proxy server. Your app handles the redirect flow:
|
|
73
|
+
### 4. Add Authentication
|
|
50
74
|
|
|
51
75
|
```typescript
|
|
52
|
-
// Login.vue
|
|
53
76
|
import { getAuthUrl, handleAuthCallback } from 'een-api-toolkit'
|
|
54
77
|
|
|
55
|
-
// Redirect
|
|
78
|
+
// Redirect to EEN login
|
|
56
79
|
const login = () => {
|
|
57
80
|
window.location.href = getAuthUrl()
|
|
58
81
|
}
|
|
59
82
|
|
|
60
|
-
// Handle
|
|
83
|
+
// Handle callback (after EEN redirects back)
|
|
61
84
|
const onCallback = async (code: string, state: string) => {
|
|
62
|
-
const {
|
|
85
|
+
const { error } = await handleAuthCallback(code, state)
|
|
63
86
|
if (error) {
|
|
64
87
|
console.error('Auth failed:', error.message)
|
|
65
88
|
return
|
|
66
89
|
}
|
|
67
|
-
// User is
|
|
90
|
+
// User is authenticated, token stored in Pinia
|
|
68
91
|
router.push('/dashboard')
|
|
69
92
|
}
|
|
70
93
|
```
|
|
71
94
|
|
|
72
|
-
|
|
95
|
+
### 5. Use the API
|
|
73
96
|
|
|
74
|
-
|
|
97
|
+
**Vue Composables (reactive):**
|
|
75
98
|
|
|
76
99
|
```vue
|
|
77
100
|
<script setup>
|
|
78
101
|
import { useCurrentUser, useUsers } from 'een-api-toolkit'
|
|
79
102
|
|
|
80
|
-
|
|
81
|
-
const {
|
|
82
|
-
|
|
83
|
-
// List all users with pagination
|
|
84
|
-
const { users, loading: usersLoading, hasNextPage, fetchNextPage } = useUsers()
|
|
103
|
+
const { user, loading, error } = useCurrentUser()
|
|
104
|
+
const { users, hasNextPage, fetchNextPage } = useUsers({ pageSize: 10 })
|
|
85
105
|
</script>
|
|
86
106
|
|
|
87
107
|
<template>
|
|
88
108
|
<div v-if="loading">Loading...</div>
|
|
89
|
-
<div v-else-if="error">
|
|
109
|
+
<div v-else-if="error">{{ error.message }}</div>
|
|
90
110
|
<div v-else>
|
|
91
111
|
<h1>Welcome, {{ user.firstName }}</h1>
|
|
92
|
-
<h2>All Users:</h2>
|
|
93
112
|
<ul>
|
|
94
113
|
<li v-for="u in users" :key="u.id">{{ u.email }}</li>
|
|
95
114
|
</ul>
|
|
96
115
|
<button v-if="hasNextPage" @click="fetchNextPage">Load More</button>
|
|
97
|
-
<button @click="refresh">Refresh</button>
|
|
98
116
|
</div>
|
|
99
117
|
</template>
|
|
100
118
|
```
|
|
101
119
|
|
|
102
|
-
|
|
120
|
+
**Plain Functions (framework-agnostic):**
|
|
103
121
|
|
|
104
122
|
```typescript
|
|
105
|
-
import { getUsers,
|
|
123
|
+
import { getUsers, getCurrentUser } from 'een-api-toolkit'
|
|
106
124
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
console.log('Users:', users)
|
|
125
|
+
// Get current authenticated user
|
|
126
|
+
const { data: currentUser, error: userError } = await getCurrentUser()
|
|
127
|
+
if (userError) {
|
|
128
|
+
console.error(userError.code, userError.message)
|
|
129
|
+
} else {
|
|
130
|
+
console.log('Current user:', currentUser.email)
|
|
114
131
|
}
|
|
115
132
|
|
|
116
|
-
//
|
|
117
|
-
const { data, error } = await
|
|
118
|
-
pageSize: 50,
|
|
119
|
-
pageToken: 'next-page-token'
|
|
120
|
-
})
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
## Error Handling
|
|
124
|
-
|
|
125
|
-
All functions return `{data, error}` objects - they never throw exceptions:
|
|
126
|
-
|
|
127
|
-
```typescript
|
|
128
|
-
const { data, error } = await getCameras()
|
|
129
|
-
|
|
133
|
+
// Get list of users
|
|
134
|
+
const { data: users, error } = await getUsers()
|
|
130
135
|
if (error) {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
break
|
|
135
|
-
case 'API_ERROR':
|
|
136
|
-
showNotification(`API Error: ${error.message}`)
|
|
137
|
-
break
|
|
138
|
-
case 'NETWORK_ERROR':
|
|
139
|
-
showNotification('Network unavailable')
|
|
140
|
-
break
|
|
141
|
-
}
|
|
142
|
-
return
|
|
136
|
+
console.error(error.code, error.message)
|
|
137
|
+
} else {
|
|
138
|
+
console.log('Users:', users.results)
|
|
143
139
|
}
|
|
144
|
-
|
|
145
|
-
// Safe to use data here
|
|
146
|
-
console.log(data)
|
|
147
|
-
```
|
|
148
|
-
|
|
149
|
-
## Configuration
|
|
150
|
-
|
|
151
|
-
### Environment Variables
|
|
152
|
-
|
|
153
|
-
Copy `.env.example` to `.env` and configure:
|
|
154
|
-
|
|
155
|
-
```env
|
|
156
|
-
# EEN OAuth Client ID (required for authentication)
|
|
157
|
-
VITE_EEN_CLIENT_ID=your-een-client-id
|
|
158
|
-
|
|
159
|
-
# Test credentials for Playwright E2E tests
|
|
160
|
-
TEST_USER=your-test-email@example.com
|
|
161
|
-
TEST_PASSWORD=your-test-password
|
|
162
|
-
|
|
163
|
-
# OAuth proxy URL (required for API calls)
|
|
164
|
-
# Use local proxy for development to avoid Cloudflare rate limits
|
|
165
|
-
VITE_PROXY_URL=http://localhost:8787
|
|
166
|
-
|
|
167
|
-
# npm access token for publishing (Automation type from npmjs.com)
|
|
168
|
-
NPM_TOKEN=npm_xxxxxxxxxxxx
|
|
169
|
-
|
|
170
|
-
# Slack webhook for notifications
|
|
171
|
-
SLACK_WEBHOOK=https://hooks.slack.com/services/xxx/xxx/xxx
|
|
172
|
-
|
|
173
|
-
# Anthropic API key for Claude code review
|
|
174
|
-
ANTHROPIC_API_KEY=sk-ant-xxxxxxxxxxxx
|
|
175
|
-
```
|
|
176
|
-
|
|
177
|
-
### GitHub Secrets
|
|
178
|
-
|
|
179
|
-
GitHub Actions workflows require these secrets. Sync them from your `.env` file:
|
|
180
|
-
|
|
181
|
-
```bash
|
|
182
|
-
# Preview what will be synced
|
|
183
|
-
./scripts/sync-secrets.sh --dry-run
|
|
184
|
-
|
|
185
|
-
# Sync secrets to GitHub
|
|
186
|
-
./scripts/sync-secrets.sh
|
|
187
|
-
```
|
|
188
|
-
|
|
189
|
-
Required secrets:
|
|
190
|
-
| Secret | Purpose |
|
|
191
|
-
|--------|---------|
|
|
192
|
-
| `VITE_EEN_CLIENT_ID` | EEN OAuth client ID |
|
|
193
|
-
| `TEST_USER` | E2E test user email |
|
|
194
|
-
| `TEST_PASSWORD` | E2E test user password |
|
|
195
|
-
| `VITE_PROXY_URL` | OAuth proxy URL |
|
|
196
|
-
| `NPM_TOKEN` | npm publish token |
|
|
197
|
-
| `SLACK_WEBHOOK` | Slack notifications |
|
|
198
|
-
| `ANTHROPIC_API_KEY` | Claude code review |
|
|
199
|
-
|
|
200
|
-
### Local Proxy Server
|
|
201
|
-
|
|
202
|
-
For development, run the local OAuth proxy to avoid Cloudflare rate limits:
|
|
203
|
-
|
|
204
|
-
```bash
|
|
205
|
-
cd ../een-oauth-proxy/proxy
|
|
206
|
-
npm run dev
|
|
207
|
-
```
|
|
208
|
-
|
|
209
|
-
This starts the proxy at `http://localhost:8787`. The proxy must be running for authentication and API calls to work.
|
|
210
|
-
|
|
211
|
-
### Running E2E Tests
|
|
212
|
-
|
|
213
|
-
E2E tests use Playwright to authenticate with EEN and test actual API calls.
|
|
214
|
-
|
|
215
|
-
**Prerequisites:**
|
|
216
|
-
1. Ensure the OAuth proxy is running:
|
|
217
|
-
```bash
|
|
218
|
-
./scripts/restart-proxy.sh
|
|
219
|
-
```
|
|
220
|
-
|
|
221
|
-
2. Set test credentials in `.env`:
|
|
222
|
-
```env
|
|
223
|
-
TEST_USER=your-test-email@example.com
|
|
224
|
-
TEST_PASSWORD=your-test-password
|
|
225
|
-
VITE_EEN_CLIENT_ID=your-client-id
|
|
226
|
-
VITE_PROXY_URL=http://localhost:8787
|
|
227
|
-
```
|
|
228
|
-
|
|
229
|
-
**Run tests:**
|
|
230
|
-
```bash
|
|
231
|
-
npm run test:e2e # Run all E2E tests
|
|
232
|
-
npm run test:e2e:ui # Run with Playwright UI
|
|
233
|
-
```
|
|
234
|
-
|
|
235
|
-
**Token caching:** Auth tokens are cached in `e2e/.auth-state.json` (with 5-minute expiry buffer) to speed up repeated test runs. Delete this file to force re-authentication.
|
|
236
|
-
|
|
237
|
-
**Security note:** The cached access token is stored in plaintext. This is acceptable for development/testing because:
|
|
238
|
-
- The token is short-lived (~1 hour)
|
|
239
|
-
- The file has restricted permissions (owner read/write only)
|
|
240
|
-
- The file is excluded from git
|
|
241
|
-
|
|
242
|
-
**Cleanup after tests:**
|
|
243
|
-
```bash
|
|
244
|
-
./scripts/cleanup-auth.sh # Revokes token and removes cache file
|
|
245
140
|
```
|
|
246
141
|
|
|
247
142
|
## Architecture
|
|
248
143
|
|
|
249
144
|
```
|
|
250
|
-
|
|
251
|
-
│
|
|
252
|
-
│
|
|
253
|
-
│ │
|
|
254
|
-
│ │ ┌──────────────┐ ┌────────────────────┐
|
|
255
|
-
│ │ │ Composables │ │ Plain Functions │
|
|
256
|
-
│ │ │ useUsers() │ │ getUsers() │
|
|
257
|
-
│ │ │
|
|
258
|
-
│ │ └──────────────┘ └────────────────────┘
|
|
259
|
-
│
|
|
260
|
-
│
|
|
261
|
-
│
|
|
262
|
-
│
|
|
263
|
-
│
|
|
264
|
-
│
|
|
265
|
-
│
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
## Key Features
|
|
281
|
-
|
|
282
|
-
- **No direct API credentials** - OAuth handled via proxy
|
|
283
|
-
- **Reactive or plain** - Choose composables for Vue reactivity, plain functions for flexibility
|
|
284
|
-
- **Predictable errors** - Always `{data, error}`, no try/catch needed
|
|
285
|
-
- **Auto token refresh** - Handled internally by the toolkit
|
|
286
|
-
- **Type-safe** - Full TypeScript types from OpenAPI spec
|
|
287
|
-
|
|
288
|
-
## Publishing (for maintainers)
|
|
289
|
-
|
|
290
|
-
The package is published to npm automatically when changes are merged to the `production` branch.
|
|
291
|
-
|
|
292
|
-
### Version Management
|
|
293
|
-
- Patch version auto-increments on each commit (via Husky pre-commit hook)
|
|
294
|
-
- Minor/major versions updated manually in `package.json`
|
|
295
|
-
|
|
296
|
-
### Release Flow
|
|
297
|
-
```
|
|
298
|
-
feature branch → develop → production → npm publish
|
|
299
|
-
```
|
|
300
|
-
|
|
301
|
-
### Manual Publish
|
|
302
|
-
```bash
|
|
303
|
-
npm login
|
|
304
|
-
npm run build
|
|
305
|
-
npm publish
|
|
145
|
+
┌──────────────────────────────────────────────────────────────────────┐
|
|
146
|
+
│ Your Vue 3 App │
|
|
147
|
+
│ ┌────────────────────────────────────────────────────────────────┐ │
|
|
148
|
+
│ │ import from 'een-api-toolkit' │ │
|
|
149
|
+
│ │ ┌──────────────┐ ┌────────────────────┐ │ │
|
|
150
|
+
│ │ │ Composables │ │ Plain Functions │ │ │
|
|
151
|
+
│ │ │ useUsers() │ │ getUsers() │ │ │
|
|
152
|
+
│ │ │ useUser() │ │ getUser() │ │ │
|
|
153
|
+
│ │ └──────────────┘ └────────────────────┘ │ │
|
|
154
|
+
│ └────────────────────────────────────────────────────────────────┘ │
|
|
155
|
+
│ │ │ │
|
|
156
|
+
│ ▼ ▼ │
|
|
157
|
+
│ ┌─────────────────────┐ ┌─────────────────────┐ │
|
|
158
|
+
│ │ Pinia Auth Store │ │ API Calls with │ │
|
|
159
|
+
│ │ (token, baseUrl) │ │ Bearer Token │ │
|
|
160
|
+
│ └─────────────────────┘ └─────────────────────┘ │
|
|
161
|
+
└────────────────────│─────────────────────────────│───────────────────┘
|
|
162
|
+
│ │
|
|
163
|
+
Auth calls │ │ API calls
|
|
164
|
+
(login/refresh) │ │ (data)
|
|
165
|
+
▼ ▼
|
|
166
|
+
┌─────────────────────┐ ┌─────────────────────┐
|
|
167
|
+
│ OAuth Proxy │ │ EEN API v3.0 │
|
|
168
|
+
│ (local or cloud) │ │ │
|
|
169
|
+
└─────────────────────┘ └─────────────────────┘
|
|
170
|
+
│
|
|
171
|
+
▼
|
|
172
|
+
┌─────────────────────┐
|
|
173
|
+
│ EEN OAuth │
|
|
174
|
+
└─────────────────────┘
|
|
306
175
|
```
|
|
307
176
|
|
|
308
177
|
## Documentation
|
|
309
178
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
179
|
+
| Document | Description |
|
|
180
|
+
|----------|-------------|
|
|
181
|
+
| **[User Guide](./docs/USER-GUIDE.md)** | Installation, proxy setup, configuration, building apps |
|
|
182
|
+
| **[Developer Guide](./docs/DEVELOPER-GUIDE.md)** | Architecture, testing, CI/CD, contributing |
|
|
183
|
+
| **[API Reference](./docs/api/)** | Auto-generated TypeDoc documentation |
|
|
184
|
+
| **[Example App](./examples/vue-basic/)** | Complete Vue 3 example with OAuth flow |
|
|
185
|
+
| **[AI Context](./docs/AI-CONTEXT.md)** | Single-file reference for AI assistants |
|
|
313
186
|
|
|
314
|
-
##
|
|
187
|
+
## External Resources
|
|
315
188
|
|
|
316
|
-
- [EEN
|
|
317
|
-
- [EEN API
|
|
189
|
+
- [EEN Developer Portal](https://developer.eagleeyenetworks.com/)
|
|
190
|
+
- [EEN API v3.0 Documentation](https://developer.eagleeyenetworks.com/reference/using-the-api)
|
|
191
|
+
- [een-oauth-proxy](https://github.com/klaushofrichter/een-oauth-proxy) - OAuth proxy server
|
|
318
192
|
|
|
319
193
|
## License
|
|
320
194
|
|
|
321
195
|
MIT
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
This repository is provided as-is without warranty. It uses EEN services but is not affiliated with Eagle Eye Networks.
|