yaver-feedback-react-native 0.8.6 → 0.8.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.
package/README.md CHANGED
@@ -16,7 +16,7 @@ Manual fallback:
16
16
  npm install yaver-feedback-react-native
17
17
  ```
18
18
 
19
- > **Mobile only.** This SDK targets React Native (iOS + Android). A `yaver-feedback-web` package exists for browser apps but currently expects a bring-your-own auth token the equivalent in-app sign-in UX (Apple / Google / GitHub / GitLab / Microsoft / email) for the web SDK will land in a future release. Open an issue if you need it sooner.
19
+ > **Mobile only.** This SDK targets React Native (iOS + Android). For browser apps use `yaver-feedback-web`, which now has its own popup OAuth, email auth, login modal, and device picker. The React Native and web SDKs share the same account/device model, but use platform-specific auth UX.
20
20
 
21
21
  ### Peer dependencies
22
22
 
@@ -1,4 +1,4 @@
1
- import { FeedbackBundle, RunnerBrowserAuthSession, TestSession, VoiceCapability } from './types';
1
+ import { CapabilitySnapshot, FeedbackBundle, IncidentEvent, OperationState, RunnerBrowserAuthSession, TestSession, VoiceCapability } from './types';
2
2
  export interface FeedbackEvent {
3
3
  type: string;
4
4
  timestamp: string;
@@ -47,6 +47,23 @@ export declare class P2PClient {
47
47
  startRunnerBrowserAuth(runner: string): Promise<RunnerBrowserAuthSession>;
48
48
  getRunnerBrowserAuthStatus(sessionId: string): Promise<RunnerBrowserAuthSession>;
49
49
  cancelRunnerBrowserAuth(sessionId: string): Promise<void>;
50
+ capabilitySnapshot(): Promise<CapabilitySnapshot | null>;
51
+ incidents(opts?: {
52
+ category?: string;
53
+ severity?: string;
54
+ code?: string;
55
+ deviceId?: string;
56
+ projectPath?: string;
57
+ includeResolved?: boolean;
58
+ limit?: number;
59
+ }): Promise<IncidentEvent[]>;
60
+ operations(opts?: {
61
+ kind?: string;
62
+ status?: string;
63
+ deviceId?: string;
64
+ projectPath?: string;
65
+ limit?: number;
66
+ }): Promise<OperationState[]>;
50
67
  /** Health check — returns true if the agent is reachable. */
51
68
  health(): Promise<boolean>;
52
69
  /** Get agent info (hostname, version, platform). */
package/dist/P2PClient.js CHANGED
@@ -155,6 +155,68 @@ class P2PClient {
155
155
  }
156
156
  catch { /* best-effort */ }
157
157
  }
158
+ async capabilitySnapshot() {
159
+ try {
160
+ const resp = await fetch(`${this.baseUrl}/capabilities/snapshot`, { headers: this.authHeaders() });
161
+ if (!resp.ok)
162
+ return null;
163
+ const data = await resp.json().catch(() => ({}));
164
+ return (data.snapshot ?? null);
165
+ }
166
+ catch {
167
+ return null;
168
+ }
169
+ }
170
+ async incidents(opts = {}) {
171
+ try {
172
+ const url = new URL(`${this.baseUrl}/incidents`);
173
+ if (opts.category)
174
+ url.searchParams.set('category', opts.category);
175
+ if (opts.severity)
176
+ url.searchParams.set('severity', opts.severity);
177
+ if (opts.code)
178
+ url.searchParams.set('code', opts.code);
179
+ if (opts.deviceId)
180
+ url.searchParams.set('device', opts.deviceId);
181
+ if (opts.projectPath)
182
+ url.searchParams.set('projectPath', opts.projectPath);
183
+ if (opts.includeResolved)
184
+ url.searchParams.set('includeResolved', '1');
185
+ if (typeof opts.limit === 'number')
186
+ url.searchParams.set('limit', String(opts.limit));
187
+ const resp = await fetch(url.toString(), { headers: this.authHeaders() });
188
+ if (!resp.ok)
189
+ return [];
190
+ const data = await resp.json().catch(() => ({}));
191
+ return Array.isArray(data.incidents) ? data.incidents : [];
192
+ }
193
+ catch {
194
+ return [];
195
+ }
196
+ }
197
+ async operations(opts = {}) {
198
+ try {
199
+ const url = new URL(`${this.baseUrl}/operations`);
200
+ if (opts.kind)
201
+ url.searchParams.set('kind', opts.kind);
202
+ if (opts.status)
203
+ url.searchParams.set('status', opts.status);
204
+ if (opts.deviceId)
205
+ url.searchParams.set('device', opts.deviceId);
206
+ if (opts.projectPath)
207
+ url.searchParams.set('projectPath', opts.projectPath);
208
+ if (typeof opts.limit === 'number')
209
+ url.searchParams.set('limit', String(opts.limit));
210
+ const resp = await fetch(url.toString(), { headers: this.authHeaders() });
211
+ if (!resp.ok)
212
+ return [];
213
+ const data = await resp.json().catch(() => ({}));
214
+ return Array.isArray(data.operations) ? data.operations : [];
215
+ }
216
+ catch {
217
+ return [];
218
+ }
219
+ }
158
220
  /** Health check — returns true if the agent is reachable. */
159
221
  async health() {
160
222
  try {
package/dist/types.d.ts CHANGED
@@ -19,6 +19,61 @@ export interface RunnerBrowserAuthSession {
19
19
  updatedAt: number;
20
20
  completedAt?: number;
21
21
  }
22
+ export interface IncidentEvent {
23
+ id: string;
24
+ timestamp: number;
25
+ severity: 'info' | 'warn' | 'error' | 'fatal';
26
+ category: string;
27
+ code: string;
28
+ source: string;
29
+ title: string;
30
+ userMessage: string;
31
+ technicalInfo?: string;
32
+ suggestedAction?: string;
33
+ operationId?: string;
34
+ deviceId?: string;
35
+ projectPath?: string;
36
+ target?: string;
37
+ logsAvailable: boolean;
38
+ logRefs?: string[];
39
+ correlationId?: string;
40
+ recoverable: boolean;
41
+ metadata?: Record<string, unknown>;
42
+ resolved?: boolean;
43
+ }
44
+ export interface OperationState {
45
+ id: string;
46
+ kind: string;
47
+ status: string;
48
+ phase?: string;
49
+ message?: string;
50
+ progress?: number;
51
+ deviceId?: string;
52
+ projectPath?: string;
53
+ startedAt: number;
54
+ updatedAt: number;
55
+ incidentIds?: string[];
56
+ metadata?: Record<string, unknown>;
57
+ }
58
+ export interface CapabilityTargetReadiness {
59
+ enabled: boolean;
60
+ reasonCode?: string;
61
+ reason?: string;
62
+ suggestedAction?: string;
63
+ notes?: string[];
64
+ }
65
+ export interface CapabilitySnapshot {
66
+ generatedAt: string;
67
+ machine?: Record<string, unknown>;
68
+ infra?: Record<string, unknown>;
69
+ connectivity?: {
70
+ directAvailable?: boolean;
71
+ relayConfigured?: boolean;
72
+ tunnelConfigured?: boolean;
73
+ tailscaleAvailable?: boolean;
74
+ };
75
+ targets: Record<string, CapabilityTargetReadiness>;
76
+ }
22
77
  export interface FeedbackConfig {
23
78
  /** URL of the Yaver agent (e.g. "http://192.168.1.10:18080"). If omitted, auto-discovery is used. */
24
79
  agentUrl?: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yaver-feedback-react-native",
3
- "version": "0.8.6",
3
+ "version": "0.8.7",
4
4
  "description": "Visual feedback SDK for Yaver \u2014 bug reports, screen recording, voice annotations, and local-first developer workflows",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/src/P2PClient.ts CHANGED
@@ -1,5 +1,13 @@
1
1
  import { Platform } from 'react-native';
2
- import { FeedbackBundle, RunnerBrowserAuthSession, TestSession, VoiceCapability } from './types';
2
+ import {
3
+ CapabilitySnapshot,
4
+ FeedbackBundle,
5
+ IncidentEvent,
6
+ OperationState,
7
+ RunnerBrowserAuthSession,
8
+ TestSession,
9
+ VoiceCapability,
10
+ } from './types';
3
11
 
4
12
  export interface FeedbackEvent {
5
13
  type: string;
@@ -191,6 +199,67 @@ export class P2PClient {
191
199
  try { await fetch(url, { method: 'POST', headers: this.authHeaders() }); } catch { /* best-effort */ }
192
200
  }
193
201
 
202
+ async capabilitySnapshot(): Promise<CapabilitySnapshot | null> {
203
+ try {
204
+ const resp = await fetch(`${this.baseUrl}/capabilities/snapshot`, { headers: this.authHeaders() });
205
+ if (!resp.ok) return null;
206
+ const data = await resp.json().catch(() => ({} as Record<string, unknown>));
207
+ return (data.snapshot ?? null) as CapabilitySnapshot | null;
208
+ } catch {
209
+ return null;
210
+ }
211
+ }
212
+
213
+ async incidents(opts: {
214
+ category?: string;
215
+ severity?: string;
216
+ code?: string;
217
+ deviceId?: string;
218
+ projectPath?: string;
219
+ includeResolved?: boolean;
220
+ limit?: number;
221
+ } = {}): Promise<IncidentEvent[]> {
222
+ try {
223
+ const url = new URL(`${this.baseUrl}/incidents`);
224
+ if (opts.category) url.searchParams.set('category', opts.category);
225
+ if (opts.severity) url.searchParams.set('severity', opts.severity);
226
+ if (opts.code) url.searchParams.set('code', opts.code);
227
+ if (opts.deviceId) url.searchParams.set('device', opts.deviceId);
228
+ if (opts.projectPath) url.searchParams.set('projectPath', opts.projectPath);
229
+ if (opts.includeResolved) url.searchParams.set('includeResolved', '1');
230
+ if (typeof opts.limit === 'number') url.searchParams.set('limit', String(opts.limit));
231
+ const resp = await fetch(url.toString(), { headers: this.authHeaders() });
232
+ if (!resp.ok) return [];
233
+ const data = await resp.json().catch(() => ({} as Record<string, unknown>));
234
+ return Array.isArray(data.incidents) ? (data.incidents as IncidentEvent[]) : [];
235
+ } catch {
236
+ return [];
237
+ }
238
+ }
239
+
240
+ async operations(opts: {
241
+ kind?: string;
242
+ status?: string;
243
+ deviceId?: string;
244
+ projectPath?: string;
245
+ limit?: number;
246
+ } = {}): Promise<OperationState[]> {
247
+ try {
248
+ const url = new URL(`${this.baseUrl}/operations`);
249
+ if (opts.kind) url.searchParams.set('kind', opts.kind);
250
+ if (opts.status) url.searchParams.set('status', opts.status);
251
+ if (opts.deviceId) url.searchParams.set('device', opts.deviceId);
252
+ if (opts.projectPath) url.searchParams.set('projectPath', opts.projectPath);
253
+ if (typeof opts.limit === 'number') url.searchParams.set('limit', String(opts.limit));
254
+ const resp = await fetch(url.toString(), { headers: this.authHeaders() });
255
+ if (!resp.ok) return [];
256
+ const data = await resp.json().catch(() => ({} as Record<string, unknown>));
257
+ return Array.isArray(data.operations) ? (data.operations as OperationState[]) : [];
258
+ } catch {
259
+ return [];
260
+ }
261
+ }
262
+
194
263
  /** Health check — returns true if the agent is reachable. */
195
264
  async health(): Promise<boolean> {
196
265
  try {
package/src/types.ts CHANGED
@@ -20,6 +20,65 @@ export interface RunnerBrowserAuthSession {
20
20
  completedAt?: number;
21
21
  }
22
22
 
23
+ export interface IncidentEvent {
24
+ id: string;
25
+ timestamp: number;
26
+ severity: 'info' | 'warn' | 'error' | 'fatal';
27
+ category: string;
28
+ code: string;
29
+ source: string;
30
+ title: string;
31
+ userMessage: string;
32
+ technicalInfo?: string;
33
+ suggestedAction?: string;
34
+ operationId?: string;
35
+ deviceId?: string;
36
+ projectPath?: string;
37
+ target?: string;
38
+ logsAvailable: boolean;
39
+ logRefs?: string[];
40
+ correlationId?: string;
41
+ recoverable: boolean;
42
+ metadata?: Record<string, unknown>;
43
+ resolved?: boolean;
44
+ }
45
+
46
+ export interface OperationState {
47
+ id: string;
48
+ kind: string;
49
+ status: string;
50
+ phase?: string;
51
+ message?: string;
52
+ progress?: number;
53
+ deviceId?: string;
54
+ projectPath?: string;
55
+ startedAt: number;
56
+ updatedAt: number;
57
+ incidentIds?: string[];
58
+ metadata?: Record<string, unknown>;
59
+ }
60
+
61
+ export interface CapabilityTargetReadiness {
62
+ enabled: boolean;
63
+ reasonCode?: string;
64
+ reason?: string;
65
+ suggestedAction?: string;
66
+ notes?: string[];
67
+ }
68
+
69
+ export interface CapabilitySnapshot {
70
+ generatedAt: string;
71
+ machine?: Record<string, unknown>;
72
+ infra?: Record<string, unknown>;
73
+ connectivity?: {
74
+ directAvailable?: boolean;
75
+ relayConfigured?: boolean;
76
+ tunnelConfigured?: boolean;
77
+ tailscaleAvailable?: boolean;
78
+ };
79
+ targets: Record<string, CapabilityTargetReadiness>;
80
+ }
81
+
23
82
  export interface FeedbackConfig {
24
83
  /** URL of the Yaver agent (e.g. "http://192.168.1.10:18080"). If omitted, auto-discovery is used. */
25
84
  agentUrl?: string;