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.
- package/README.md +23 -0
- package/dist/MachinePickerScreen.js +2 -2
- package/dist/YaverFeedback.js +178 -30
- package/dist/__tests__/AuthDevices.test.js +7 -7
- package/dist/__tests__/BlackBox.hotReload.test.d.ts +1 -0
- package/dist/__tests__/BlackBox.hotReload.test.js +204 -0
- package/dist/__tests__/P2PClient.test.js +56 -0
- package/dist/__tests__/YaverFeedback.test.js +9 -0
- package/dist/__tests__/types.test.js +2 -0
- package/dist/_core/constants.d.ts +6 -2
- package/dist/_core/constants.js +6 -2
- package/dist/types.d.ts +29 -0
- package/package.json +1 -1
- package/src/MachinePickerScreen.tsx +2 -2
- package/src/YaverFeedback.ts +174 -30
- package/src/__tests__/AuthDevices.test.ts +7 -7
- package/src/__tests__/BlackBox.hotReload.test.ts +226 -0
- package/src/__tests__/P2PClient.test.ts +70 -0
- package/src/__tests__/YaverFeedback.test.ts +11 -0
- package/src/__tests__/types.test.ts +2 -0
- package/src/_core/constants.ts +6 -2
- package/src/types.ts +29 -0
|
@@ -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
|
|
package/src/_core/constants.ts
CHANGED
|
@@ -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 =
|
|
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.
|