een-api-toolkit 0.3.38 → 0.3.46
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/.claude/agents/docs-accuracy-reviewer.md +35 -5
- package/.claude/agents/een-auth-agent.md +28 -0
- package/.claude/agents/een-automations-agent.md +264 -0
- package/.claude/agents/een-devices-agent.md +5 -7
- package/.claude/agents/een-events-agent.md +40 -18
- package/.claude/agents/een-media-agent.md +12 -15
- package/.claude/agents/een-setup-agent.md +32 -0
- package/.claude/agents/een-users-agent.md +2 -2
- package/CHANGELOG.md +9 -75
- package/dist/index.cjs +3 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +815 -0
- package/dist/index.js +986 -719
- package/dist/index.js.map +1 -1
- package/docs/AI-CONTEXT.md +17 -1
- package/docs/ai-reference/AI-AUTH.md +42 -1
- package/docs/ai-reference/AI-AUTOMATIONS.md +833 -0
- package/docs/ai-reference/AI-DEVICES.md +1 -1
- package/docs/ai-reference/AI-EVENTS.md +2 -2
- package/docs/ai-reference/AI-GROUPING.md +128 -66
- package/docs/ai-reference/AI-MEDIA.md +1 -1
- package/docs/ai-reference/AI-SETUP.md +1 -1
- package/docs/ai-reference/AI-USERS.md +1 -1
- package/examples/vue-alerts-metrics/src/App.vue +7 -1
- package/examples/vue-automations/.env.example +11 -0
- package/examples/vue-automations/README.md +205 -0
- package/examples/vue-automations/e2e/app.spec.ts +83 -0
- package/examples/vue-automations/e2e/auth.spec.ts +468 -0
- package/examples/vue-automations/index.html +13 -0
- package/examples/vue-automations/package-lock.json +1722 -0
- package/examples/vue-automations/package.json +29 -0
- package/examples/vue-automations/playwright.config.ts +46 -0
- package/examples/vue-automations/src/App.vue +122 -0
- package/examples/vue-automations/src/main.ts +23 -0
- package/examples/vue-automations/src/router/index.ts +61 -0
- package/examples/vue-automations/src/views/Automations.vue +692 -0
- package/examples/vue-automations/src/views/Callback.vue +76 -0
- package/examples/vue-automations/src/views/Home.vue +172 -0
- package/examples/vue-automations/src/views/Login.vue +33 -0
- package/examples/vue-automations/src/views/Logout.vue +66 -0
- package/examples/vue-automations/src/vite-env.d.ts +1 -0
- package/examples/vue-automations/tsconfig.json +21 -0
- package/examples/vue-automations/tsconfig.node.json +10 -0
- package/examples/vue-automations/vite.config.ts +12 -0
- package/examples/vue-bridges/e2e/auth.spec.ts +97 -0
- package/examples/vue-bridges/src/App.vue +7 -1
- package/examples/vue-cameras/src/App.vue +7 -1
- package/examples/vue-event-subscriptions/src/App.vue +7 -1
- package/examples/vue-event-subscriptions/src/views/LiveEvents.vue +1 -1
- package/examples/vue-events/src/App.vue +7 -1
- package/examples/vue-layouts/src/App.vue +7 -1
- package/examples/vue-users/package-lock.json +2 -2
- package/examples/vue-users/package.json +1 -1
- package/examples/vue-users/src/App.vue +7 -1
- package/package.json +1 -1
|
@@ -31,6 +31,13 @@ assistant: "I'll use the docs-accuracy-reviewer agent to verify the README and a
|
|
|
31
31
|
<Task tool call to launch docs-accuracy-reviewer agent>
|
|
32
32
|
</example>
|
|
33
33
|
|
|
34
|
+
<example>
|
|
35
|
+
Context: User wants to verify Claude agent definitions are accurate.
|
|
36
|
+
user: "Check if the agent files in .claude/agents match the actual API"
|
|
37
|
+
assistant: "I'll use the docs-accuracy-reviewer agent to verify the een-* agent files have correct function signatures, parameter names, and code examples."
|
|
38
|
+
<Task tool call to launch docs-accuracy-reviewer agent>
|
|
39
|
+
</example>
|
|
40
|
+
|
|
34
41
|
## Your Core Responsibilities
|
|
35
42
|
|
|
36
43
|
1. **Function and Feature Verification**: Cross-reference every documented function, method, API, and feature against the actual source code. Verify that:
|
|
@@ -62,8 +69,8 @@ assistant: "I'll use the docs-accuracy-reviewer agent to verify the README and a
|
|
|
62
69
|
1. **Discovery Phase**:
|
|
63
70
|
- List all markdown files in the project (README.md, docs/**, CLAUDE.md, etc.)
|
|
64
71
|
- **Scan ALL example directories** (`examples/*/README.md`) - do not skip any
|
|
65
|
-
- Check agent files in `.claude/agents
|
|
66
|
-
- Identify the source code structure for cross-referencing
|
|
72
|
+
- **Check ALL agent files** in `.claude/agents/een-*.md` - verify function signatures and code examples against actual implementations
|
|
73
|
+
- Identify the source code structure for cross-referencing (especially `src/index.ts` exports, `src/*/service.ts` implementations, and `src/types/*.ts` definitions)
|
|
67
74
|
|
|
68
75
|
2. **Analysis Phase**:
|
|
69
76
|
- Read each documentation file thoroughly
|
|
@@ -115,6 +122,18 @@ assistant: "I'll use the docs-accuracy-reviewer agent to verify the README and a
|
|
|
115
122
|
- Verify .env.example matches documentation
|
|
116
123
|
- Check that all required secrets are documented
|
|
117
124
|
|
|
125
|
+
### For Claude Agent Files (`.claude/agents/een-*.md`):
|
|
126
|
+
- **Function Signatures**: Verify all documented function signatures match actual implementations in `src/*/service.ts`
|
|
127
|
+
- **Parameter Names**: Check that parameter names in examples match the actual API (e.g., `deviceId` not `cameraId`, `userId` as direct param not `{ id: userId }`)
|
|
128
|
+
- **Result Properties**: Verify result property names (e.g., `imageData` not `dataUrl`)
|
|
129
|
+
- **Type Definitions**: Cross-reference documented types against `src/types/*.ts`
|
|
130
|
+
- **Filter Parameters**: Verify filter parameter names use correct suffixes (e.g., `startTimestamp__gte` not `startTimestamp`)
|
|
131
|
+
- **Include Options**: Check that documented include options are valid for each API
|
|
132
|
+
- **Code Examples**: Ensure all code examples use current API patterns and would actually compile
|
|
133
|
+
- **Referenced Examples**: Verify that referenced example directories (`examples/vue-*/`) exist
|
|
134
|
+
- **Referenced Docs**: Verify that referenced documentation files (`docs/ai-reference/AI-*.md`) exist
|
|
135
|
+
- **Version Consistency**: If version numbers are present, verify they match `package.json`
|
|
136
|
+
|
|
118
137
|
## Output Format
|
|
119
138
|
|
|
120
139
|
When reporting findings, use this structure:
|
|
@@ -153,6 +172,17 @@ When reporting findings, use this structure:
|
|
|
153
172
|
Before completing your review:
|
|
154
173
|
1. Verify you've checked ALL markdown files in the project
|
|
155
174
|
2. **Confirm ALL example app READMEs were reviewed** (list them in your report)
|
|
156
|
-
3. Confirm
|
|
157
|
-
4.
|
|
158
|
-
5.
|
|
175
|
+
3. **Confirm ALL `.claude/agents/een-*.md` files were reviewed** for API accuracy
|
|
176
|
+
4. Confirm each fix you made is backed by evidence from source code
|
|
177
|
+
5. Re-read modified sections to ensure they're clear and accurate
|
|
178
|
+
6. Check that your fixes didn't introduce new broken links or inconsistencies
|
|
179
|
+
|
|
180
|
+
## Common Agent File Issues to Watch For
|
|
181
|
+
|
|
182
|
+
These are the most common inaccuracies found in agent files:
|
|
183
|
+
- Using `cameraId` instead of `deviceId` for media/image functions
|
|
184
|
+
- Using `{ id: userId }` instead of `userId` as direct parameter for get functions
|
|
185
|
+
- Using `dataUrl` instead of `imageData` for image result properties
|
|
186
|
+
- Using `startTimestamp` instead of `startTimestamp__gte` for event filters
|
|
187
|
+
- Using `width/height` instead of `targetWidth/targetHeight` for image dimensions
|
|
188
|
+
- Missing `formatTimestamp()` calls for timestamp parameters
|
|
@@ -122,6 +122,32 @@ authStore.isAuthenticated // Computed: true if valid token exists
|
|
|
122
122
|
authStore.isExpired // Computed: true if token expired
|
|
123
123
|
```
|
|
124
124
|
|
|
125
|
+
### authStore.initialize() - Session Restoration (CRITICAL)
|
|
126
|
+
**Must be called in App.vue onMounted to restore sessions from storage.**
|
|
127
|
+
|
|
128
|
+
Without this call, users must re-login after every page refresh, even with localStorage strategy:
|
|
129
|
+
|
|
130
|
+
```vue
|
|
131
|
+
<script setup lang="ts">
|
|
132
|
+
import { onMounted, computed } from 'vue'
|
|
133
|
+
import { useAuthStore } from 'een-api-toolkit'
|
|
134
|
+
|
|
135
|
+
const authStore = useAuthStore()
|
|
136
|
+
const isAuthenticated = computed(() => authStore.isAuthenticated)
|
|
137
|
+
|
|
138
|
+
// CRITICAL: Restore session from storage on app mount
|
|
139
|
+
onMounted(() => {
|
|
140
|
+
authStore.initialize()
|
|
141
|
+
})
|
|
142
|
+
</script>
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
What `initialize()` does:
|
|
146
|
+
1. Loads token, expiration, session ID, base URL from storage
|
|
147
|
+
2. If valid token exists: Sets up auto-refresh timer
|
|
148
|
+
3. If expired token: Clears auth state (user must re-login)
|
|
149
|
+
4. If no token: No action (user must login)
|
|
150
|
+
|
|
125
151
|
## Auth Guard Pattern
|
|
126
152
|
|
|
127
153
|
**CRITICAL**: The OAuth callback check MUST come BEFORE the auth check in the global guard.
|
|
@@ -297,3 +323,5 @@ async function clearAuthState(page: Page): Promise<void> {
|
|
|
297
323
|
| invalid_grant | Code expired or reused | Restart OAuth flow |
|
|
298
324
|
| invalid_state | State mismatch | Clear storage, restart flow |
|
|
299
325
|
| REFRESH_FAILED | Refresh token invalid | Redirect to login |
|
|
326
|
+
| Session lost on refresh | Missing initialize() call | Add `authStore.initialize()` in App.vue onMounted |
|
|
327
|
+
| Must login after refresh | Missing initialize() call | Add `authStore.initialize()` in App.vue onMounted |
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: een-automations-agent
|
|
3
|
+
description: |
|
|
4
|
+
Use this agent when working with automation rules: event alert condition rules,
|
|
5
|
+
alert condition rules, alert action rules, or alert actions with the een-api-toolkit.
|
|
6
|
+
This includes setting up automated alert workflows and notifications.
|
|
7
|
+
model: inherit
|
|
8
|
+
color: orange
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
You are an expert in automation rules and alert workflows with the een-api-toolkit.
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
<example>
|
|
16
|
+
Context: User wants to list automation rules.
|
|
17
|
+
user: "How do I list all my alert condition rules?"
|
|
18
|
+
assistant: "I'll use the een-automations-agent to help list alert condition rules with listAlertConditionRules()."
|
|
19
|
+
<Task tool call to launch een-automations-agent>
|
|
20
|
+
</example>
|
|
21
|
+
|
|
22
|
+
<example>
|
|
23
|
+
Context: User wants to see available alert actions.
|
|
24
|
+
user: "What alert actions are configured for my account?"
|
|
25
|
+
assistant: "I'll use the een-automations-agent to help fetch alert actions with listAlertActions()."
|
|
26
|
+
<Task tool call to launch een-automations-agent>
|
|
27
|
+
</example>
|
|
28
|
+
|
|
29
|
+
<example>
|
|
30
|
+
Context: User wants to understand the automation workflow.
|
|
31
|
+
user: "How do events trigger alerts and actions?"
|
|
32
|
+
assistant: "I'll use the een-automations-agent to explain the event-to-alert-to-action workflow."
|
|
33
|
+
<Task tool call to launch een-automations-agent>
|
|
34
|
+
</example>
|
|
35
|
+
|
|
36
|
+
## Context Files
|
|
37
|
+
- docs/AI-CONTEXT.md (overview)
|
|
38
|
+
- docs/ai-reference/AI-AUTH.md (auth is required)
|
|
39
|
+
- docs/ai-reference/AI-AUTOMATIONS.md (primary reference)
|
|
40
|
+
- docs/ai-reference/AI-EVENTS.md (events trigger alerts)
|
|
41
|
+
|
|
42
|
+
## Reference Examples
|
|
43
|
+
- examples/vue-automations/ (Automation rules listing)
|
|
44
|
+
|
|
45
|
+
## Your Capabilities
|
|
46
|
+
1. List event alert condition rules with listEventAlertConditionRules()
|
|
47
|
+
2. Get available filter values with getEventAlertConditionRuleFieldValues()
|
|
48
|
+
3. Get single event alert condition rule with getEventAlertConditionRule()
|
|
49
|
+
4. List alert condition rules with listAlertConditionRules()
|
|
50
|
+
5. Get single alert condition rule with getAlertConditionRule()
|
|
51
|
+
6. List alert action rules with listAlertActionRules()
|
|
52
|
+
7. Get single alert action rule with getAlertActionRule()
|
|
53
|
+
8. List alert actions with listAlertActions()
|
|
54
|
+
9. Get single alert action with getAlertAction()
|
|
55
|
+
|
|
56
|
+
## Automation Workflow
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
Events → Event Alert Condition Rules → Alerts → Alert Action Rules → Alert Actions
|
|
60
|
+
(filter events) (generated) (match alerts) (execute)
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
1. **Events** are generated by cameras/devices (motion, object detection, etc.)
|
|
64
|
+
2. **Event Alert Condition Rules** filter events and determine when to create alerts
|
|
65
|
+
3. **Alerts** are generated when events match rule conditions
|
|
66
|
+
4. **Alert Action Rules** match alerts to actions based on type, actor, priority
|
|
67
|
+
5. **Alert Actions** execute (push notification, webhook, SMS, email, etc.)
|
|
68
|
+
|
|
69
|
+
## Key Types
|
|
70
|
+
|
|
71
|
+
### EventAlertConditionRule
|
|
72
|
+
```typescript
|
|
73
|
+
interface EventAlertConditionRule {
|
|
74
|
+
id: string
|
|
75
|
+
name: string
|
|
76
|
+
priority: number // 1-10, higher is more important
|
|
77
|
+
enabled: boolean
|
|
78
|
+
cooldownSeconds: number
|
|
79
|
+
eventFilter: {
|
|
80
|
+
types: string[] // Event types to match
|
|
81
|
+
resourceFilter?: {
|
|
82
|
+
actorIds?: string[]
|
|
83
|
+
actorTags__contains?: string[]
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
outputAlertTypes: string[] // Alert types generated
|
|
87
|
+
humanValidation?: {
|
|
88
|
+
required: boolean
|
|
89
|
+
timeoutSeconds?: number
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### AlertConditionRule
|
|
95
|
+
```typescript
|
|
96
|
+
interface AlertConditionRule {
|
|
97
|
+
id: string
|
|
98
|
+
name: string
|
|
99
|
+
type: string
|
|
100
|
+
enabled: boolean
|
|
101
|
+
priority: number
|
|
102
|
+
actors: AlertConditionRuleActor[] // Actors this rule applies to
|
|
103
|
+
inputEventTypes: string[] // Event types that trigger this rule
|
|
104
|
+
outputAlertType: string // Alert type generated
|
|
105
|
+
actions?: AlertConditionRuleAction[] // include=actions
|
|
106
|
+
insights?: AlertConditionRuleInsights // include=insights
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### AlertActionRule
|
|
111
|
+
```typescript
|
|
112
|
+
interface AlertActionRule {
|
|
113
|
+
id: string
|
|
114
|
+
name: string
|
|
115
|
+
enabled: boolean
|
|
116
|
+
alertTypes: string[] // Alert types this rule matches
|
|
117
|
+
actorIds: string[]
|
|
118
|
+
actorTypes: string[]
|
|
119
|
+
ruleIds: string[] // Alert condition rule IDs
|
|
120
|
+
alertActionIds: string[] // Actions to execute
|
|
121
|
+
priority__gte?: number // Min priority filter
|
|
122
|
+
priority__lte?: number // Max priority filter
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### AutomationAlertAction
|
|
127
|
+
```typescript
|
|
128
|
+
interface AutomationAlertAction {
|
|
129
|
+
id: string
|
|
130
|
+
type: AlertActionType
|
|
131
|
+
name: string
|
|
132
|
+
enabled: boolean
|
|
133
|
+
settings: AlertActionSettings // Type-specific settings
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
type AlertActionType =
|
|
137
|
+
| 'notification' // Push notifications
|
|
138
|
+
| 'sms' // SMS messages
|
|
139
|
+
| 'smtp' // Email
|
|
140
|
+
| 'slack' // Slack webhook
|
|
141
|
+
| 'webhook' // Generic webhook
|
|
142
|
+
| 'brivo' // Brivo access control
|
|
143
|
+
| 'zendesk' // Zendesk tickets
|
|
144
|
+
| 'immix' // Immix integration
|
|
145
|
+
| 'zapier' // Zapier webhook
|
|
146
|
+
| 'sentinel' // Sentinel integration
|
|
147
|
+
| 'evalinkTalos' // Evalink integration
|
|
148
|
+
| 'outputPort' // Physical output trigger
|
|
149
|
+
| 'ebus' // eBus integration
|
|
150
|
+
| 'playSpeakerAudioClip' // Speaker audio
|
|
151
|
+
| 'zulipPrivate' // Zulip private message
|
|
152
|
+
| 'zulipStream' // Zulip stream message
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## Key Functions
|
|
156
|
+
|
|
157
|
+
### listEventAlertConditionRules()
|
|
158
|
+
```typescript
|
|
159
|
+
import { listEventAlertConditionRules, type EventAlertConditionRule } from 'een-api-toolkit'
|
|
160
|
+
|
|
161
|
+
const { data, error } = await listEventAlertConditionRules({
|
|
162
|
+
enabled: true,
|
|
163
|
+
priority__gte: 5,
|
|
164
|
+
pageSize: 50
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
if (data) {
|
|
168
|
+
data.results.forEach(rule => {
|
|
169
|
+
console.log(`${rule.name}: ${rule.eventFilter.types.join(', ')}`)
|
|
170
|
+
})
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### listAlertConditionRules()
|
|
175
|
+
```typescript
|
|
176
|
+
import { listAlertConditionRules } from 'een-api-toolkit'
|
|
177
|
+
|
|
178
|
+
const { data, error } = await listAlertConditionRules({
|
|
179
|
+
enabled: true,
|
|
180
|
+
include: ['actions', 'insights']
|
|
181
|
+
})
|
|
182
|
+
|
|
183
|
+
if (data) {
|
|
184
|
+
data.results.forEach(rule => {
|
|
185
|
+
console.log(`${rule.name}: ${rule.actions?.length ?? 0} actions`)
|
|
186
|
+
console.log(`Last triggered: ${rule.insights?.lastTriggered}`)
|
|
187
|
+
})
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### listAlertActionRules()
|
|
192
|
+
```typescript
|
|
193
|
+
import { listAlertActionRules } from 'een-api-toolkit'
|
|
194
|
+
|
|
195
|
+
const { data, error } = await listAlertActionRules({
|
|
196
|
+
enabled: true,
|
|
197
|
+
alertType__in: ['een.motionDetectionAlert.v1']
|
|
198
|
+
})
|
|
199
|
+
|
|
200
|
+
if (data) {
|
|
201
|
+
data.results.forEach(rule => {
|
|
202
|
+
console.log(`${rule.name}: ${rule.alertActionIds.length} actions`)
|
|
203
|
+
})
|
|
204
|
+
}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### listAlertActions()
|
|
208
|
+
```typescript
|
|
209
|
+
import { listAlertActions } from 'een-api-toolkit'
|
|
210
|
+
|
|
211
|
+
const { data, error } = await listAlertActions({
|
|
212
|
+
enabled: true,
|
|
213
|
+
type__in: ['notification', 'webhook', 'slack']
|
|
214
|
+
})
|
|
215
|
+
|
|
216
|
+
if (data) {
|
|
217
|
+
data.results.forEach(action => {
|
|
218
|
+
console.log(`${action.name} (${action.type})`)
|
|
219
|
+
})
|
|
220
|
+
}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### getEventAlertConditionRuleFieldValues()
|
|
224
|
+
Discover available filter values:
|
|
225
|
+
```typescript
|
|
226
|
+
import { getEventAlertConditionRuleFieldValues } from 'een-api-toolkit'
|
|
227
|
+
|
|
228
|
+
const { data } = await getEventAlertConditionRuleFieldValues()
|
|
229
|
+
if (data) {
|
|
230
|
+
console.log('Available event types:', data.eventTypes)
|
|
231
|
+
console.log('Available alert types:', data.outputAlertTypes)
|
|
232
|
+
}
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
## Filter Patterns
|
|
236
|
+
|
|
237
|
+
| Filter | Example | Description |
|
|
238
|
+
|--------|---------|-------------|
|
|
239
|
+
| `enabled` | `true` | Filter by enabled/disabled status |
|
|
240
|
+
| `id__in` | `['id1', 'id2']` | Filter by specific IDs |
|
|
241
|
+
| `priority__gte` | `5` | Minimum priority (inclusive) |
|
|
242
|
+
| `priority__lte` | `10` | Maximum priority (inclusive) |
|
|
243
|
+
| `outputAlertType__in` | `['een.motionDetectionAlert.v1']` | Event alert rule output types |
|
|
244
|
+
| `alertType__in` | `['een.motionDetectionAlert.v1']` | Alert action rule alert types |
|
|
245
|
+
| `type__in` | `['notification', 'webhook']` | Alert action types |
|
|
246
|
+
| `actorId__in` | `['camera-123']` | Filter by actor IDs |
|
|
247
|
+
| `include` | `['actions', 'insights']` | Include additional fields |
|
|
248
|
+
|
|
249
|
+
## Error Handling
|
|
250
|
+
|
|
251
|
+
| Error Code | Meaning | Action |
|
|
252
|
+
|------------|---------|--------|
|
|
253
|
+
| AUTH_REQUIRED | Not authenticated | Redirect to login |
|
|
254
|
+
| NOT_FOUND | Rule/action not found | Show "not found" message |
|
|
255
|
+
| FORBIDDEN | No permission | Show access denied |
|
|
256
|
+
| RATE_LIMITED | Too many requests | Retry with backoff |
|
|
257
|
+
| VALIDATION_ERROR | Invalid parameters | Check input |
|
|
258
|
+
|
|
259
|
+
## Constraints
|
|
260
|
+
- All automation endpoints are GET-only (read access)
|
|
261
|
+
- Priority values range from 1-10 (higher = more important)
|
|
262
|
+
- Use `include` parameter for additional data (actions, insights)
|
|
263
|
+
- Pagination is supported on all list endpoints
|
|
264
|
+
- Filter by `enabled` to see only active rules/actions
|
|
@@ -170,14 +170,13 @@ async function getCamerasByTags(tags: string[]) {
|
|
|
170
170
|
}
|
|
171
171
|
```
|
|
172
172
|
|
|
173
|
-
### getCamera(
|
|
173
|
+
### getCamera(cameraId, params?)
|
|
174
174
|
Get a specific camera:
|
|
175
175
|
```typescript
|
|
176
176
|
import { getCamera, type Camera } from 'een-api-toolkit'
|
|
177
177
|
|
|
178
178
|
async function fetchCamera(cameraId: string) {
|
|
179
|
-
const result = await getCamera({
|
|
180
|
-
id: cameraId,
|
|
179
|
+
const result = await getCamera(cameraId, {
|
|
181
180
|
include: ['deviceInfo', 'settings'] // Request additional details
|
|
182
181
|
})
|
|
183
182
|
|
|
@@ -216,14 +215,13 @@ async function fetchOnlineBridges() {
|
|
|
216
215
|
}
|
|
217
216
|
```
|
|
218
217
|
|
|
219
|
-
### getBridge(
|
|
218
|
+
### getBridge(bridgeId, params?)
|
|
220
219
|
Get a specific bridge:
|
|
221
220
|
```typescript
|
|
222
221
|
import { getBridge, type Bridge } from 'een-api-toolkit'
|
|
223
222
|
|
|
224
223
|
async function fetchBridge(bridgeId: string) {
|
|
225
|
-
const result = await getBridge({
|
|
226
|
-
id: bridgeId,
|
|
224
|
+
const result = await getBridge(bridgeId, {
|
|
227
225
|
include: ['networkInfo']
|
|
228
226
|
})
|
|
229
227
|
|
|
@@ -334,7 +332,7 @@ onMounted(fetchCameras)
|
|
|
334
332
|
The `camera.id` property is used consistently across all toolkit functions:
|
|
335
333
|
- `getCameras()` returns cameras with `id` property
|
|
336
334
|
- `listFeeds({ deviceId: camera.id })` for feeds
|
|
337
|
-
- `getLiveImage({
|
|
335
|
+
- `getLiveImage({ deviceId: camera.id })` for images
|
|
338
336
|
- LivePlayer SDK: `{ cameraId: camera.id }` for live video
|
|
339
337
|
|
|
340
338
|
**Note:** Some legacy EEN documentation may refer to "ESN" (Electronic Serial Number). This is outdated terminology - the current API uses `id`. In the toolkit, always use `camera.id`.
|
|
@@ -79,12 +79,14 @@ type EventType =
|
|
|
79
79
|
```typescript
|
|
80
80
|
interface ListEventsParams {
|
|
81
81
|
actor: string // Required: "camera:{cameraId}"
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
82
|
+
type__in: string[] // Required: event types to query
|
|
83
|
+
startTimestamp__gte: string // Required: start time (ISO 8601)
|
|
84
|
+
startTimestamp__lte?: string // Optional: end time filter
|
|
85
|
+
endTimestamp__gte?: string // Optional: filter by event end time
|
|
86
|
+
endTimestamp__lte?: string // Optional: filter by event end time
|
|
85
87
|
pageSize?: number
|
|
86
88
|
pageToken?: string
|
|
87
|
-
include?: string[] // Include SVG overlays: ['data.
|
|
89
|
+
include?: string[] // Include SVG overlays: ['data.een.fullFrameImageUrl.v1']
|
|
88
90
|
}
|
|
89
91
|
```
|
|
90
92
|
|
|
@@ -118,10 +120,10 @@ async function fetchEvents(cameraId: string) {
|
|
|
118
120
|
|
|
119
121
|
const result = await listEvents({
|
|
120
122
|
actor: `camera:${cameraId}`,
|
|
121
|
-
startTimestamp: formatTimestamp(hourAgo),
|
|
122
|
-
endTimestamp: formatTimestamp(now),
|
|
123
123
|
type__in: ['een.motionDetectionEvent.v1', 'een.objectDetectionEvent.v1'],
|
|
124
|
-
|
|
124
|
+
startTimestamp__gte: formatTimestamp(hourAgo.toISOString()),
|
|
125
|
+
startTimestamp__lte: formatTimestamp(now.toISOString()),
|
|
126
|
+
include: ['data.een.fullFrameImageUrl.v1'], // Include image URLs
|
|
125
127
|
pageSize: 50
|
|
126
128
|
})
|
|
127
129
|
|
|
@@ -250,6 +252,19 @@ async function fetchAlerts() {
|
|
|
250
252
|
}
|
|
251
253
|
```
|
|
252
254
|
|
|
255
|
+
### Alert Priority
|
|
256
|
+
Alert priority is an integer value ranging from **0 to 10**:
|
|
257
|
+
- `0` = Lowest priority
|
|
258
|
+
- `10` = Highest priority
|
|
259
|
+
|
|
260
|
+
Use priority to filter or sort alerts by importance:
|
|
261
|
+
```typescript
|
|
262
|
+
const result = await listAlerts({
|
|
263
|
+
priority__gte: 7, // High priority alerts only
|
|
264
|
+
status__in: ['active']
|
|
265
|
+
})
|
|
266
|
+
```
|
|
267
|
+
|
|
253
268
|
### listNotifications()
|
|
254
269
|
Get user notifications:
|
|
255
270
|
```typescript
|
|
@@ -269,12 +284,20 @@ async function fetchNotifications() {
|
|
|
269
284
|
|
|
270
285
|
## SSE (Server-Sent Events) for Real-Time Updates
|
|
271
286
|
|
|
287
|
+
### SSE Subscription Behavior
|
|
288
|
+
|
|
289
|
+
**Important: TTL is read-only and server-determined**
|
|
290
|
+
- SSE subscriptions have a **15-minute TTL** (900 seconds) set by the server
|
|
291
|
+
- The `timeToLiveSeconds` value **cannot be customized** when creating a subscription
|
|
292
|
+
- The `subscriptionConfig` (including `lifeCycle` and `timeToLiveSeconds`) is returned in the API response but is not a configurable input
|
|
293
|
+
- SSE URLs are **single-use**: once disconnected, you must create a new subscription
|
|
294
|
+
|
|
272
295
|
### SSE Lifecycle
|
|
273
296
|
|
|
274
|
-
1. **Create Subscription** - Get a subscription with SSE URL
|
|
297
|
+
1. **Create Subscription** - Get a subscription with SSE URL (server sets 15-min TTL)
|
|
275
298
|
2. **Connect to Stream** - Open EventSource connection
|
|
276
299
|
3. **Handle Events** - Process events as they arrive
|
|
277
|
-
4. **Cleanup** - Delete subscription when done
|
|
300
|
+
4. **Cleanup** - Delete subscription when done (or it auto-expires after 15 min of inactivity)
|
|
278
301
|
|
|
279
302
|
### createEventSubscription()
|
|
280
303
|
```typescript
|
|
@@ -337,23 +360,22 @@ onUnmounted(async () => {
|
|
|
337
360
|
|
|
338
361
|
Use `getRecordedImage()` to fetch a thumbnail image for an event:
|
|
339
362
|
```typescript
|
|
340
|
-
import { getRecordedImage, type Event } from 'een-api-toolkit'
|
|
363
|
+
import { getRecordedImage, formatTimestamp, type Event } from 'een-api-toolkit'
|
|
341
364
|
|
|
342
365
|
const eventImages = ref<Map<string, string>>(new Map())
|
|
343
366
|
|
|
344
367
|
async function fetchEventThumbnail(event: Event) {
|
|
345
|
-
// Extract
|
|
346
|
-
const
|
|
368
|
+
// Extract device ID from actorId
|
|
369
|
+
const deviceId = event.actorId
|
|
347
370
|
|
|
348
371
|
const result = await getRecordedImage({
|
|
349
|
-
|
|
350
|
-
timestamp: event.
|
|
351
|
-
|
|
352
|
-
height: 80
|
|
372
|
+
deviceId,
|
|
373
|
+
timestamp: formatTimestamp(event.startTimestamp),
|
|
374
|
+
type: 'preview'
|
|
353
375
|
})
|
|
354
376
|
|
|
355
|
-
if (result.data?.
|
|
356
|
-
eventImages.value.set(event.id, result.data.
|
|
377
|
+
if (result.data?.imageData) {
|
|
378
|
+
eventImages.value.set(event.id, result.data.imageData)
|
|
357
379
|
}
|
|
358
380
|
}
|
|
359
381
|
|
|
@@ -87,23 +87,21 @@ If you need HD quality video, you MUST use the Live Video SDK. Do not attempt to
|
|
|
87
87
|
|
|
88
88
|
## Key Functions
|
|
89
89
|
|
|
90
|
-
### getLiveImage(
|
|
91
|
-
Get a live preview image (returns data URL):
|
|
90
|
+
### getLiveImage(params)
|
|
91
|
+
Get a live preview image (returns base64 data URL):
|
|
92
92
|
```typescript
|
|
93
93
|
import { getLiveImage, type LiveImageResult } from 'een-api-toolkit'
|
|
94
94
|
|
|
95
95
|
const imageUrl = ref<string>('')
|
|
96
96
|
|
|
97
|
-
async function fetchPreview(
|
|
97
|
+
async function fetchPreview(deviceId: string) {
|
|
98
98
|
const result = await getLiveImage({
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
height: 240,
|
|
102
|
-
type: 'jpeg'
|
|
99
|
+
deviceId,
|
|
100
|
+
type: 'preview' // Optional, defaults to 'preview'
|
|
103
101
|
})
|
|
104
102
|
|
|
105
103
|
if (result.data) {
|
|
106
|
-
imageUrl.value = result.data.
|
|
104
|
+
imageUrl.value = result.data.imageData // Use directly in <img src>
|
|
107
105
|
}
|
|
108
106
|
}
|
|
109
107
|
```
|
|
@@ -158,21 +156,20 @@ onMounted(async () => {
|
|
|
158
156
|
})
|
|
159
157
|
```
|
|
160
158
|
|
|
161
|
-
### getRecordedImage()
|
|
159
|
+
### getRecordedImage(params)
|
|
162
160
|
Get an image at a specific timestamp:
|
|
163
161
|
```typescript
|
|
164
162
|
import { getRecordedImage, formatTimestamp } from 'een-api-toolkit'
|
|
165
163
|
|
|
166
|
-
async function fetchRecordedFrame(
|
|
164
|
+
async function fetchRecordedFrame(deviceId: string, date: Date) {
|
|
167
165
|
const result = await getRecordedImage({
|
|
168
|
-
|
|
169
|
-
timestamp: formatTimestamp(date), // MUST use formatTimestamp()
|
|
170
|
-
|
|
171
|
-
height: 480
|
|
166
|
+
deviceId,
|
|
167
|
+
timestamp: formatTimestamp(date.toISOString()), // MUST use formatTimestamp()
|
|
168
|
+
type: 'preview' // Optional, defaults to 'preview'
|
|
172
169
|
})
|
|
173
170
|
|
|
174
171
|
if (result.data) {
|
|
175
|
-
imageUrl.value = result.data.
|
|
172
|
+
imageUrl.value = result.data.imageData
|
|
176
173
|
}
|
|
177
174
|
}
|
|
178
175
|
```
|
|
@@ -74,6 +74,35 @@ app.use(router)
|
|
|
74
74
|
app.mount('#app')
|
|
75
75
|
```
|
|
76
76
|
|
|
77
|
+
### App.vue Session Restoration (CRITICAL)
|
|
78
|
+
**Users will need to re-login after every page refresh unless you call `authStore.initialize()` in App.vue.**
|
|
79
|
+
|
|
80
|
+
```vue
|
|
81
|
+
<script setup lang="ts">
|
|
82
|
+
import { onMounted, computed } from 'vue'
|
|
83
|
+
import { useAuthStore } from 'een-api-toolkit'
|
|
84
|
+
|
|
85
|
+
const authStore = useAuthStore()
|
|
86
|
+
const isAuthenticated = computed(() => authStore.isAuthenticated)
|
|
87
|
+
|
|
88
|
+
// CRITICAL: Initialize auth store from storage on app mount
|
|
89
|
+
// This restores the session if a valid token exists in localStorage/sessionStorage
|
|
90
|
+
onMounted(() => {
|
|
91
|
+
authStore.initialize()
|
|
92
|
+
})
|
|
93
|
+
</script>
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Without `initialize()`:
|
|
97
|
+
- Token is saved to localStorage after login ✓
|
|
98
|
+
- On page refresh, Pinia store starts with empty state
|
|
99
|
+
- `isAuthenticated` returns false → user must login again
|
|
100
|
+
|
|
101
|
+
With `initialize()`:
|
|
102
|
+
- Token is loaded from localStorage on app mount
|
|
103
|
+
- `isAuthenticated` returns true → session is restored
|
|
104
|
+
- User can continue without re-logging in
|
|
105
|
+
|
|
77
106
|
### vite.config.ts for EEN OAuth
|
|
78
107
|
```typescript
|
|
79
108
|
import { defineConfig } from 'vite'
|
|
@@ -115,6 +144,7 @@ export default router
|
|
|
115
144
|
- Pinia must be installed before initEenToolkit()
|
|
116
145
|
- Never add trailing slashes to redirect URIs
|
|
117
146
|
- Ensure VITE_PROXY_URL is set in .env file
|
|
147
|
+
- **Always call `authStore.initialize()` in App.vue onMounted** for session persistence
|
|
118
148
|
|
|
119
149
|
## Common Errors and Solutions
|
|
120
150
|
|
|
@@ -124,3 +154,5 @@ export default router
|
|
|
124
154
|
| "redirect_uri mismatch" | Wrong host/port | Use 127.0.0.1:3333 in vite.config.ts |
|
|
125
155
|
| "Invalid redirect_uri" | Trailing slash | Remove trailing slash from redirect URI |
|
|
126
156
|
| "CORS error" | Proxy not running | Start the OAuth proxy server |
|
|
157
|
+
| Session lost on refresh | Missing initialize() call | Add `authStore.initialize()` in App.vue onMounted |
|
|
158
|
+
| Must login after refresh | Missing initialize() call | Add `authStore.initialize()` in App.vue onMounted |
|
|
@@ -137,13 +137,13 @@ async function loadMore() {
|
|
|
137
137
|
}
|
|
138
138
|
```
|
|
139
139
|
|
|
140
|
-
### getUser(
|
|
140
|
+
### getUser(userId, params?)
|
|
141
141
|
Get a specific user by ID:
|
|
142
142
|
```typescript
|
|
143
143
|
import { getUser, type User } from 'een-api-toolkit'
|
|
144
144
|
|
|
145
145
|
async function fetchUser(userId: string) {
|
|
146
|
-
const result = await getUser(
|
|
146
|
+
const result = await getUser(userId)
|
|
147
147
|
|
|
148
148
|
if (result.error) {
|
|
149
149
|
if (result.error.code === 'NOT_FOUND') {
|