yaver-feedback-react-native 0.8.7 → 0.8.9

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.
@@ -254,5 +254,75 @@ describe('P2PClient', () => {
254
254
  }),
255
255
  );
256
256
  });
257
+
258
+ it('dev mode hits /dev/reload with bearer auth', async () => {
259
+ mockFetch.mockResolvedValue({
260
+ ok: true,
261
+ json: () => Promise.resolve({ ok: true }),
262
+ });
263
+ const client = new P2PClient('http://localhost:18080', 'tok');
264
+ await client.reloadApp('dev');
265
+ expect(mockFetch).toHaveBeenCalledWith(
266
+ 'http://localhost:18080/dev/reload',
267
+ expect.objectContaining({
268
+ method: 'POST',
269
+ headers: expect.objectContaining({ Authorization: 'Bearer tok' }),
270
+ }),
271
+ );
272
+ });
273
+
274
+ it('bundle mode hits /dev/reload-app with mode + projectName in body', async () => {
275
+ mockFetch.mockResolvedValue({
276
+ ok: true,
277
+ json: () => Promise.resolve({ ok: true }),
278
+ });
279
+ const client = new P2PClient('http://localhost:18080', 'tok');
280
+ await client.reloadApp('bundle', { projectName: 'sfmg' });
281
+ const [url, init] = mockFetch.mock.calls[0];
282
+ expect(url).toBe('http://localhost:18080/dev/reload-app');
283
+ expect(init.method).toBe('POST');
284
+ expect(JSON.parse(init.body as string)).toEqual(
285
+ expect.objectContaining({ mode: 'bundle', projectName: 'sfmg' }),
286
+ );
287
+ expect(init.headers).toEqual(
288
+ expect.objectContaining({
289
+ Authorization: 'Bearer tok',
290
+ 'Content-Type': 'application/json',
291
+ }),
292
+ );
293
+ });
294
+
295
+ it('dev mode falls back to /dev/reload-app when /dev/reload 4xxs', async () => {
296
+ // First call: /dev/reload 404. Second: /dev/reload-app 200.
297
+ mockFetch
298
+ .mockResolvedValueOnce({ ok: false, status: 404, json: () => Promise.resolve({}) })
299
+ .mockResolvedValueOnce({ ok: true, json: () => Promise.resolve({ ok: true }) });
300
+
301
+ const client = new P2PClient('http://localhost:18080', 'tok');
302
+ const result = await client.reloadApp('dev', { projectName: 'sfmg' });
303
+
304
+ expect(mockFetch).toHaveBeenCalledTimes(2);
305
+ expect(mockFetch.mock.calls[0][0]).toBe('http://localhost:18080/dev/reload');
306
+ expect(mockFetch.mock.calls[1][0]).toBe('http://localhost:18080/dev/reload-app');
307
+ expect(result.ok).toBe(true);
308
+ });
309
+
310
+ it('surfaces nativeChangesDetected so the host can prompt for rebuild', async () => {
311
+ mockFetch.mockResolvedValue({
312
+ ok: true,
313
+ json: () =>
314
+ Promise.resolve({
315
+ ok: true,
316
+ nativeChangesDetected: true,
317
+ changeClass: 'native_required',
318
+ }),
319
+ });
320
+ const client = new P2PClient('http://localhost:18080', 'tok');
321
+ const result = await client.reloadApp('dev');
322
+ expect(result.nativeChangesDetected).toBe(true);
323
+ expect(result.changeClass).toBe('native_required');
324
+ // Caller-visible message must distinguish native-required from JS-only.
325
+ expect(result.message).toMatch(/native|rebuild/i);
326
+ });
257
327
  });
258
328
  });
@@ -83,6 +83,17 @@ describe('YaverFeedback', () => {
83
83
  expect(cfg!.strictNativeAuth).toBe(true);
84
84
  });
85
85
 
86
+ it('promotes quick icon to always when shake is disabled', () => {
87
+ YaverFeedback.init({
88
+ authToken: 'tok',
89
+ disableShakeGesture: true,
90
+ });
91
+
92
+ const cfg = YaverFeedback.getConfig();
93
+ expect(cfg!.disableShakeGesture).toBe(true);
94
+ expect(cfg!.quickIcon).toBe('always');
95
+ });
96
+
86
97
  it('with enabled=false sets enabled to false', () => {
87
98
  YaverFeedback.init({
88
99
  authToken: 'tok',
@@ -27,11 +27,13 @@ describe('React Native SDK types', () => {
27
27
  authToken: 'tok',
28
28
  agentUrl: 'http://192.168.1.10:18080',
29
29
  trigger: 'shake',
30
+ disableShakeGesture: true,
30
31
  enabled: true,
31
32
  maxRecordingDuration: 60,
32
33
  strictNativeAuth: true,
33
34
  };
34
35
  expect(config.trigger).toBe('shake');
36
+ expect(config.disableShakeGesture).toBe(true);
35
37
  expect(config.strictNativeAuth).toBe(true);
36
38
  });
37
39
 
@@ -57,9 +57,13 @@ export const DEFAULT_BEACON_UDP_PORT = 19837;
57
57
  /**
58
58
  * How old an agent's last heartbeat can be before the device is
59
59
  * considered offline. Mirrors `backend/convex/devices.ts` so
60
- * Convex + every client agree on the same threshold.
60
+ * Convex + every client agree on the same threshold. The agent
61
+ * heartbeats every 5 min (see `desktop/agent/main.go::heartbeatLoop`),
62
+ * so 6 min tolerates one missed beat + 60 s of jitter without
63
+ * flapping. Sub-minute death detection comes from the P2P bus, not
64
+ * this threshold.
61
65
  */
62
- export const HEARTBEAT_STALE_MS = 90_000;
66
+ export const HEARTBEAT_STALE_MS = 360_000;
63
67
 
64
68
  /**
65
69
  * How long after the last UDP beacon an agent is still considered
package/src/types.ts CHANGED
@@ -123,6 +123,35 @@ export interface FeedbackConfig {
123
123
  preferredDeviceId?: string;
124
124
  /** How feedback collection is triggered */
125
125
  trigger?: 'shake' | 'floating-button' | 'manual';
126
+ /**
127
+ * Non-default escape hatch for host apps that want the SDK without
128
+ * shake gesture handling. When enabled:
129
+ * - the SDK does not start ShakeDetector
130
+ * - if `quickIcon` was left as `'auto'`/unset, it is promoted to `'always'`
131
+ * - the app should rely on the draggable quick icon or explicit
132
+ * `YaverFeedback.startReport()` calls instead
133
+ *
134
+ * Intended for builds where another surface owns motion / haptics.
135
+ */
136
+ disableShakeGesture?: boolean;
137
+ /**
138
+ * Auto-open the BlackBox SSE command channel after init() returns.
139
+ *
140
+ * Default: `true` (0.8.8+). Listens for `reload`, `reload_bundle`,
141
+ * and `status` commands the agent broadcasts after a vibe-coding
142
+ * task commits a fix — drives the auto-reload loop without the host
143
+ * app needing to call `BlackBox.start()` manually.
144
+ *
145
+ * The auto-start is deferred 500ms after init() and gated on having
146
+ * BOTH `agentUrl` and `authToken` resolved, to avoid the iOS 18.3.1
147
+ * rope-string SIGSEGV that the early auto-start in 0.7.6 hit when
148
+ * the agent was in needs-auth mode (tight 401-retry loop in SSE).
149
+ *
150
+ * Set `false` if your host app wants to gate BlackBox start on its
151
+ * own state machine (e.g. only after the user opts into telemetry).
152
+ * Calling `BlackBox.start()` manually is still safe — it's idempotent.
153
+ */
154
+ autoStartBlackBox?: boolean;
126
155
  /**
127
156
  * Small tap-to-open icon that floats above the app so the user
128
157
  * doesn't have to shake every time they want to open feedback.