yaver-feedback-react-native 0.9.8 → 0.9.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.
|
@@ -111,9 +111,16 @@ const DogfoodQuickControls = () => {
|
|
|
111
111
|
const capability = react_native_1.DeviceEventEmitter.addListener('yaverDogfoodControlCapability', () => {
|
|
112
112
|
void refresh();
|
|
113
113
|
});
|
|
114
|
+
// Enrollment approval and Exit Dogfood both change SDK mode while this
|
|
115
|
+
// component remains mounted. Refresh React state immediately; native
|
|
116
|
+
// setEnabled() alone cannot make the fallback Y appear or disappear.
|
|
117
|
+
const mode = react_native_1.DeviceEventEmitter.addListener('yaverFeedback:dogfoodChanged', () => {
|
|
118
|
+
void refresh();
|
|
119
|
+
});
|
|
114
120
|
return () => {
|
|
115
121
|
trigger.remove();
|
|
116
122
|
capability.remove();
|
|
123
|
+
mode.remove();
|
|
117
124
|
};
|
|
118
125
|
}, [refresh]);
|
|
119
126
|
(0, react_1.useEffect)(() => {
|
package/dist/YaverFeedback.js
CHANGED
|
@@ -1090,6 +1090,16 @@ class YaverFeedback {
|
|
|
1090
1090
|
}
|
|
1091
1091
|
return base;
|
|
1092
1092
|
}
|
|
1093
|
+
// Backend approval makes the installation eligible; it does not mean the
|
|
1094
|
+
// tester is currently in Dogfood. Keep all in-app controls absent until
|
|
1095
|
+
// enableDeviceDogfood() has minted a live scoped session, and make Exit
|
|
1096
|
+
// Dogfood actually remove both the gesture and fallback Y.
|
|
1097
|
+
if (!YaverFeedback.getDogfoodStatus().active) {
|
|
1098
|
+
if (typeof native?.setEnabled === 'function') {
|
|
1099
|
+
await native.setEnabled(false, 900).catch(() => undefined);
|
|
1100
|
+
}
|
|
1101
|
+
return { ...base, reason: 'dogfood-session-inactive' };
|
|
1102
|
+
}
|
|
1093
1103
|
if (IS_HOST_MODE || isRunningInsideYaverHost()) {
|
|
1094
1104
|
if (typeof native?.setEnabled === 'function') {
|
|
1095
1105
|
await native.setEnabled(false, 900).catch(() => undefined);
|
|
@@ -69,6 +69,25 @@ beforeEach(() => {
|
|
|
69
69
|
jest.restoreAllMocks();
|
|
70
70
|
jest.clearAllMocks();
|
|
71
71
|
});
|
|
72
|
+
function activeDogfood(controlGesture = true) {
|
|
73
|
+
return {
|
|
74
|
+
enabled: true,
|
|
75
|
+
appId: 'io.example.app',
|
|
76
|
+
installationId: 'phone-1',
|
|
77
|
+
installationStatus: 'active',
|
|
78
|
+
controlGesture,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
function initActiveDogfood(options = {}) {
|
|
82
|
+
const controlGesture = options.controlGesture ?? true;
|
|
83
|
+
YaverFeedback_1.YaverFeedback.init({
|
|
84
|
+
authToken: options.authToken,
|
|
85
|
+
bundleId: 'io.example.app',
|
|
86
|
+
dogfood: { controlGesture },
|
|
87
|
+
});
|
|
88
|
+
Object.assign(YaverFeedback_1.YaverFeedback.getConfig().dogfood, activeDogfood(controlGesture));
|
|
89
|
+
jest.clearAllMocks();
|
|
90
|
+
}
|
|
72
91
|
describe('YaverFeedback', () => {
|
|
73
92
|
describe('Dogfood onboarding', () => {
|
|
74
93
|
it('starts with Yaver OAuth when the host has no session', async () => {
|
|
@@ -175,8 +194,7 @@ describe('YaverFeedback', () => {
|
|
|
175
194
|
.toHaveBeenCalledWith(false, 'Dogfood');
|
|
176
195
|
});
|
|
177
196
|
it('keeps the Y visible until the authorized phone has completed onboarding', async () => {
|
|
178
|
-
|
|
179
|
-
YaverFeedback_1.YaverFeedback.getConfig().dogfood.controlGesture = true;
|
|
197
|
+
initActiveDogfood();
|
|
180
198
|
jest.spyOn(YaverFeedback_1.YaverFeedback, 'getDogfoodAccess').mockResolvedValueOnce({
|
|
181
199
|
appId: 'io.example.app',
|
|
182
200
|
yaverAuthenticated: true,
|
|
@@ -197,8 +215,7 @@ describe('YaverFeedback', () => {
|
|
|
197
215
|
expect(react_native_1.NativeModules.YaverDogfoodGesture.setEnabled).toHaveBeenCalledWith(false, 900);
|
|
198
216
|
});
|
|
199
217
|
it('uses the invisible three-finger hold only after onboarding selects it', async () => {
|
|
200
|
-
|
|
201
|
-
YaverFeedback_1.YaverFeedback.getConfig().dogfood.controlGesture = true;
|
|
218
|
+
initActiveDogfood();
|
|
202
219
|
jest.spyOn(YaverFeedback_1.YaverFeedback, 'getDogfoodAccess').mockResolvedValueOnce({
|
|
203
220
|
appId: 'io.example.app',
|
|
204
221
|
yaverAuthenticated: true,
|
|
@@ -221,8 +238,7 @@ describe('YaverFeedback', () => {
|
|
|
221
238
|
expect(react_native_1.NativeModules.YaverDogfoodGesture.setEnabled).toHaveBeenCalledWith(true, 900);
|
|
222
239
|
});
|
|
223
240
|
it('keeps the Y when native capability reports support but enabling the gesture fails', async () => {
|
|
224
|
-
|
|
225
|
-
YaverFeedback_1.YaverFeedback.getConfig().dogfood.controlGesture = true;
|
|
241
|
+
initActiveDogfood();
|
|
226
242
|
jest.spyOn(YaverFeedback_1.YaverFeedback, 'getDogfoodAccess').mockResolvedValueOnce({
|
|
227
243
|
appId: 'io.example.app',
|
|
228
244
|
yaverAuthenticated: true,
|
|
@@ -249,8 +265,7 @@ describe('YaverFeedback', () => {
|
|
|
249
265
|
});
|
|
250
266
|
});
|
|
251
267
|
it('persists first-run completion for the exact account app installation', async () => {
|
|
252
|
-
|
|
253
|
-
YaverFeedback_1.YaverFeedback.getConfig().dogfood.controlGesture = true;
|
|
268
|
+
initActiveDogfood({ authToken: 'owner-token' });
|
|
254
269
|
jest.spyOn(YaverFeedback_1.YaverFeedback, 'getDogfoodAccess').mockResolvedValueOnce({
|
|
255
270
|
appId: 'io.example.app',
|
|
256
271
|
yaverAuthenticated: true,
|
|
@@ -272,8 +287,7 @@ describe('YaverFeedback', () => {
|
|
|
272
287
|
}));
|
|
273
288
|
});
|
|
274
289
|
it('falls back to the minimized Y when accessibility owns multi-touch', async () => {
|
|
275
|
-
|
|
276
|
-
YaverFeedback_1.YaverFeedback.getConfig().dogfood.controlGesture = { durationMs: 1200 };
|
|
290
|
+
initActiveDogfood({ controlGesture: { durationMs: 1200 } });
|
|
277
291
|
jest.spyOn(YaverFeedback_1.YaverFeedback, 'getDogfoodAccess').mockResolvedValueOnce({
|
|
278
292
|
appId: 'io.example.app',
|
|
279
293
|
yaverAuthenticated: true,
|
|
@@ -294,13 +308,24 @@ describe('YaverFeedback', () => {
|
|
|
294
308
|
expect(react_native_1.NativeModules.YaverDogfoodGesture.setEnabled).toHaveBeenCalledWith(false, 1200);
|
|
295
309
|
});
|
|
296
310
|
it('suppresses guest controls inside the Yaver split-view container', async () => {
|
|
297
|
-
|
|
298
|
-
YaverFeedback_1.YaverFeedback.getConfig().dogfood.controlGesture = true;
|
|
311
|
+
initActiveDogfood();
|
|
299
312
|
react_native_1.NativeModules.YaverInfo = { isYaver: true };
|
|
300
313
|
const state = await YaverFeedback_1.YaverFeedback.syncDogfoodControlGesture();
|
|
301
314
|
delete react_native_1.NativeModules.YaverInfo;
|
|
302
315
|
expect(state).toMatchObject({ gestureEnabled: false, fallbackVisible: false, reason: 'yaver-host-owns-controls' });
|
|
303
316
|
});
|
|
317
|
+
it('removes the gesture and fallback Y when Dogfood exits', async () => {
|
|
318
|
+
initActiveDogfood();
|
|
319
|
+
await YaverFeedback_1.YaverFeedback.exitDogfoodMode();
|
|
320
|
+
const state = await YaverFeedback_1.YaverFeedback.syncDogfoodControlGesture();
|
|
321
|
+
expect(state).toMatchObject({
|
|
322
|
+
authorized: false,
|
|
323
|
+
gestureEnabled: false,
|
|
324
|
+
fallbackVisible: false,
|
|
325
|
+
reason: 'dogfood-session-inactive',
|
|
326
|
+
});
|
|
327
|
+
expect(react_native_1.NativeModules.YaverDogfoodGesture.setEnabled).toHaveBeenCalledWith(false, 900);
|
|
328
|
+
});
|
|
304
329
|
});
|
|
305
330
|
describe('init()', () => {
|
|
306
331
|
it('sets config correctly with defaults', () => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "yaver-feedback-react-native",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.9",
|
|
4
4
|
"description": "Visual feedback SDK for Yaver — bug reports, screen recording, voice vibe coding, and local-first developer workflows",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -95,9 +95,16 @@ export const DogfoodQuickControls: React.FC = () => {
|
|
|
95
95
|
const capability = DeviceEventEmitter.addListener('yaverDogfoodControlCapability', () => {
|
|
96
96
|
void refresh();
|
|
97
97
|
});
|
|
98
|
+
// Enrollment approval and Exit Dogfood both change SDK mode while this
|
|
99
|
+
// component remains mounted. Refresh React state immediately; native
|
|
100
|
+
// setEnabled() alone cannot make the fallback Y appear or disappear.
|
|
101
|
+
const mode = DeviceEventEmitter.addListener('yaverFeedback:dogfoodChanged', () => {
|
|
102
|
+
void refresh();
|
|
103
|
+
});
|
|
98
104
|
return () => {
|
|
99
105
|
trigger.remove();
|
|
100
106
|
capability.remove();
|
|
107
|
+
mode.remove();
|
|
101
108
|
};
|
|
102
109
|
}, [refresh]);
|
|
103
110
|
|
package/src/YaverFeedback.ts
CHANGED
|
@@ -1077,6 +1077,16 @@ export class YaverFeedback {
|
|
|
1077
1077
|
}
|
|
1078
1078
|
return base;
|
|
1079
1079
|
}
|
|
1080
|
+
// Backend approval makes the installation eligible; it does not mean the
|
|
1081
|
+
// tester is currently in Dogfood. Keep all in-app controls absent until
|
|
1082
|
+
// enableDeviceDogfood() has minted a live scoped session, and make Exit
|
|
1083
|
+
// Dogfood actually remove both the gesture and fallback Y.
|
|
1084
|
+
if (!YaverFeedback.getDogfoodStatus().active) {
|
|
1085
|
+
if (typeof native?.setEnabled === 'function') {
|
|
1086
|
+
await native.setEnabled(false, 900).catch(() => undefined);
|
|
1087
|
+
}
|
|
1088
|
+
return { ...base, reason: 'dogfood-session-inactive' };
|
|
1089
|
+
}
|
|
1080
1090
|
if (IS_HOST_MODE || isRunningInsideYaverHost()) {
|
|
1081
1091
|
if (typeof native?.setEnabled === 'function') {
|
|
1082
1092
|
await native.setEnabled(false, 900).catch(() => undefined);
|
|
@@ -72,6 +72,27 @@ beforeEach(() => {
|
|
|
72
72
|
jest.clearAllMocks();
|
|
73
73
|
});
|
|
74
74
|
|
|
75
|
+
function activeDogfood(controlGesture: true | { durationMs: number } = true) {
|
|
76
|
+
return {
|
|
77
|
+
enabled: true,
|
|
78
|
+
appId: 'io.example.app',
|
|
79
|
+
installationId: 'phone-1',
|
|
80
|
+
installationStatus: 'active' as const,
|
|
81
|
+
controlGesture,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function initActiveDogfood(options: { authToken?: string; controlGesture?: true | { durationMs: number } } = {}) {
|
|
86
|
+
const controlGesture = options.controlGesture ?? true;
|
|
87
|
+
YaverFeedback.init({
|
|
88
|
+
authToken: options.authToken,
|
|
89
|
+
bundleId: 'io.example.app',
|
|
90
|
+
dogfood: { controlGesture },
|
|
91
|
+
});
|
|
92
|
+
Object.assign(YaverFeedback.getConfig()!.dogfood!, activeDogfood(controlGesture));
|
|
93
|
+
jest.clearAllMocks();
|
|
94
|
+
}
|
|
95
|
+
|
|
75
96
|
describe('YaverFeedback', () => {
|
|
76
97
|
describe('Dogfood onboarding', () => {
|
|
77
98
|
it('starts with Yaver OAuth when the host has no session', async () => {
|
|
@@ -187,8 +208,7 @@ describe('YaverFeedback', () => {
|
|
|
187
208
|
});
|
|
188
209
|
|
|
189
210
|
it('keeps the Y visible until the authorized phone has completed onboarding', async () => {
|
|
190
|
-
|
|
191
|
-
YaverFeedback.getConfig()!.dogfood!.controlGesture = true;
|
|
211
|
+
initActiveDogfood();
|
|
192
212
|
jest.spyOn(YaverFeedback, 'getDogfoodAccess').mockResolvedValueOnce({
|
|
193
213
|
appId: 'io.example.app',
|
|
194
214
|
yaverAuthenticated: true,
|
|
@@ -210,8 +230,7 @@ describe('YaverFeedback', () => {
|
|
|
210
230
|
});
|
|
211
231
|
|
|
212
232
|
it('uses the invisible three-finger hold only after onboarding selects it', async () => {
|
|
213
|
-
|
|
214
|
-
YaverFeedback.getConfig()!.dogfood!.controlGesture = true;
|
|
233
|
+
initActiveDogfood();
|
|
215
234
|
jest.spyOn(YaverFeedback, 'getDogfoodAccess').mockResolvedValueOnce({
|
|
216
235
|
appId: 'io.example.app',
|
|
217
236
|
yaverAuthenticated: true,
|
|
@@ -235,8 +254,7 @@ describe('YaverFeedback', () => {
|
|
|
235
254
|
});
|
|
236
255
|
|
|
237
256
|
it('keeps the Y when native capability reports support but enabling the gesture fails', async () => {
|
|
238
|
-
|
|
239
|
-
YaverFeedback.getConfig()!.dogfood!.controlGesture = true;
|
|
257
|
+
initActiveDogfood();
|
|
240
258
|
jest.spyOn(YaverFeedback, 'getDogfoodAccess').mockResolvedValueOnce({
|
|
241
259
|
appId: 'io.example.app',
|
|
242
260
|
yaverAuthenticated: true,
|
|
@@ -264,8 +282,7 @@ describe('YaverFeedback', () => {
|
|
|
264
282
|
});
|
|
265
283
|
|
|
266
284
|
it('persists first-run completion for the exact account app installation', async () => {
|
|
267
|
-
|
|
268
|
-
YaverFeedback.getConfig()!.dogfood!.controlGesture = true;
|
|
285
|
+
initActiveDogfood({ authToken: 'owner-token' });
|
|
269
286
|
jest.spyOn(YaverFeedback, 'getDogfoodAccess').mockResolvedValueOnce({
|
|
270
287
|
appId: 'io.example.app',
|
|
271
288
|
yaverAuthenticated: true,
|
|
@@ -288,8 +305,7 @@ describe('YaverFeedback', () => {
|
|
|
288
305
|
});
|
|
289
306
|
|
|
290
307
|
it('falls back to the minimized Y when accessibility owns multi-touch', async () => {
|
|
291
|
-
|
|
292
|
-
YaverFeedback.getConfig()!.dogfood!.controlGesture = { durationMs: 1200 };
|
|
308
|
+
initActiveDogfood({ controlGesture: { durationMs: 1200 } });
|
|
293
309
|
jest.spyOn(YaverFeedback, 'getDogfoodAccess').mockResolvedValueOnce({
|
|
294
310
|
appId: 'io.example.app',
|
|
295
311
|
yaverAuthenticated: true,
|
|
@@ -311,13 +327,25 @@ describe('YaverFeedback', () => {
|
|
|
311
327
|
});
|
|
312
328
|
|
|
313
329
|
it('suppresses guest controls inside the Yaver split-view container', async () => {
|
|
314
|
-
|
|
315
|
-
YaverFeedback.getConfig()!.dogfood!.controlGesture = true;
|
|
330
|
+
initActiveDogfood();
|
|
316
331
|
(NativeModules as any).YaverInfo = { isYaver: true };
|
|
317
332
|
const state = await YaverFeedback.syncDogfoodControlGesture();
|
|
318
333
|
delete (NativeModules as any).YaverInfo;
|
|
319
334
|
expect(state).toMatchObject({ gestureEnabled: false, fallbackVisible: false, reason: 'yaver-host-owns-controls' });
|
|
320
335
|
});
|
|
336
|
+
|
|
337
|
+
it('removes the gesture and fallback Y when Dogfood exits', async () => {
|
|
338
|
+
initActiveDogfood();
|
|
339
|
+
await YaverFeedback.exitDogfoodMode();
|
|
340
|
+
const state = await YaverFeedback.syncDogfoodControlGesture();
|
|
341
|
+
expect(state).toMatchObject({
|
|
342
|
+
authorized: false,
|
|
343
|
+
gestureEnabled: false,
|
|
344
|
+
fallbackVisible: false,
|
|
345
|
+
reason: 'dogfood-session-inactive',
|
|
346
|
+
});
|
|
347
|
+
expect((NativeModules as any).YaverDogfoodGesture.setEnabled).toHaveBeenCalledWith(false, 900);
|
|
348
|
+
});
|
|
321
349
|
});
|
|
322
350
|
|
|
323
351
|
describe('init()', () => {
|