yaver-feedback-react-native 0.9.7 → 0.9.8
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 +39 -7
- package/android/src/main/java/io/yaver/feedback/YaverDogfoodGestureModule.java +241 -0
- package/android/src/main/java/io/yaver/feedback/YaverHotReloadPackage.java +1 -0
- package/app.plugin.js +12 -2
- package/dist/AuthOverlay.js +13 -2
- package/dist/DogfoodQuickControls.d.ts +8 -0
- package/dist/DogfoodQuickControls.js +394 -0
- package/dist/DogfoodSessionUi.d.ts +50 -0
- package/dist/DogfoodSessionUi.js +135 -0
- package/dist/FeedbackModal.js +50 -22
- package/dist/YaverFeedback.d.ts +35 -1
- package/dist/YaverFeedback.js +302 -12
- package/dist/__tests__/NativeDogfoodShortcut.test.js +14 -0
- package/dist/__tests__/YaverFeedback.test.js +148 -0
- package/dist/auth.d.ts +15 -0
- package/dist/auth.js +41 -2
- package/dist/dogfoodPolicy.d.ts +22 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.js +8 -2
- package/dist/preferences.d.ts +13 -0
- package/dist/preferences.js +84 -0
- package/ios/YaverDogfoodGesture.m +14 -0
- package/ios/YaverDogfoodGesture.swift +175 -0
- package/package.json +1 -1
- package/src/AuthOverlay.tsx +20 -3
- package/src/DogfoodQuickControls.tsx +454 -0
- package/src/DogfoodSessionUi.tsx +213 -0
- package/src/FeedbackModal.tsx +62 -34
- package/src/YaverFeedback.ts +333 -12
- package/src/__tests__/NativeDogfoodShortcut.test.ts +15 -0
- package/src/__tests__/YaverFeedback.test.ts +155 -0
- package/src/auth.ts +53 -2
- package/src/dogfoodPolicy.ts +22 -1
- package/src/index.ts +13 -1
- package/src/preferences.ts +89 -0
package/src/auth.ts
CHANGED
|
@@ -207,7 +207,12 @@ export async function clearSelectedDeviceId(): Promise<void> {
|
|
|
207
207
|
export async function getDogfoodAccountAccess(appId: string, token: string, installationId?: string): Promise<{
|
|
208
208
|
authenticated: boolean;
|
|
209
209
|
ownerAuthorized: boolean;
|
|
210
|
+
accountAuthorized: boolean;
|
|
210
211
|
installationAuthorized: boolean;
|
|
212
|
+
controlPresentation?: 'auto' | 'minimized-y';
|
|
213
|
+
gestureSupported?: boolean;
|
|
214
|
+
gestureCapabilityReason?: string;
|
|
215
|
+
controlOnboardingSeen?: boolean;
|
|
211
216
|
}> {
|
|
212
217
|
try {
|
|
213
218
|
const controller = new AbortController();
|
|
@@ -219,15 +224,61 @@ export async function getDogfoodAccountAccess(appId: string, token: string, inst
|
|
|
219
224
|
signal: controller.signal,
|
|
220
225
|
});
|
|
221
226
|
clearTimeout(timeout);
|
|
222
|
-
if (!response.ok) return { authenticated: false, ownerAuthorized: false, installationAuthorized: false };
|
|
227
|
+
if (!response.ok) return { authenticated: false, ownerAuthorized: false, accountAuthorized: false, installationAuthorized: false };
|
|
223
228
|
const result = await response.json();
|
|
224
229
|
return {
|
|
225
230
|
authenticated: result?.authenticated === true,
|
|
226
231
|
ownerAuthorized: result?.ownerAuthorized === true,
|
|
232
|
+
accountAuthorized: result?.accountAuthorized === true,
|
|
227
233
|
installationAuthorized: result?.installationAuthorized === true,
|
|
234
|
+
controlPresentation: result?.controlPresentation === 'minimized-y' ? 'minimized-y'
|
|
235
|
+
: result?.controlPresentation === 'auto' ? 'auto' : undefined,
|
|
236
|
+
gestureSupported: typeof result?.gestureSupported === 'boolean' ? result.gestureSupported : undefined,
|
|
237
|
+
gestureCapabilityReason: typeof result?.gestureCapabilityReason === 'string'
|
|
238
|
+
? result.gestureCapabilityReason
|
|
239
|
+
: undefined,
|
|
240
|
+
controlOnboardingSeen: result?.controlOnboardingSeen === true,
|
|
228
241
|
};
|
|
229
242
|
} catch {
|
|
230
|
-
return { authenticated: false, ownerAuthorized: false, installationAuthorized: false };
|
|
243
|
+
return { authenticated: false, ownerAuthorized: false, accountAuthorized: false, installationAuthorized: false };
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
export async function setDogfoodControlPreference(input: {
|
|
248
|
+
appId: string;
|
|
249
|
+
installationId: string;
|
|
250
|
+
token: string;
|
|
251
|
+
presentation: 'auto' | 'minimized-y';
|
|
252
|
+
gestureSupported: boolean;
|
|
253
|
+
gestureCapabilityReason: string;
|
|
254
|
+
gesturePlatform: string;
|
|
255
|
+
controlOnboardingSeen?: boolean;
|
|
256
|
+
}): Promise<boolean> {
|
|
257
|
+
const controller = new AbortController();
|
|
258
|
+
const timeout = setTimeout(() => controller.abort(), 5_000);
|
|
259
|
+
try {
|
|
260
|
+
const response = await fetch(`${convexSiteUrl}/dogfood/control-preference`, {
|
|
261
|
+
method: 'POST',
|
|
262
|
+
headers: {
|
|
263
|
+
Authorization: `Bearer ${input.token}`,
|
|
264
|
+
'Content-Type': 'application/json',
|
|
265
|
+
},
|
|
266
|
+
body: JSON.stringify({
|
|
267
|
+
appId: input.appId,
|
|
268
|
+
installationId: input.installationId,
|
|
269
|
+
presentation: input.presentation,
|
|
270
|
+
gestureSupported: input.gestureSupported,
|
|
271
|
+
gestureCapabilityReason: input.gestureCapabilityReason,
|
|
272
|
+
gesturePlatform: input.gesturePlatform,
|
|
273
|
+
controlOnboardingSeen: input.controlOnboardingSeen === true,
|
|
274
|
+
}),
|
|
275
|
+
signal: controller.signal,
|
|
276
|
+
});
|
|
277
|
+
return response.ok;
|
|
278
|
+
} catch {
|
|
279
|
+
return false;
|
|
280
|
+
} finally {
|
|
281
|
+
clearTimeout(timeout);
|
|
231
282
|
}
|
|
232
283
|
}
|
|
233
284
|
|
package/src/dogfoodPolicy.ts
CHANGED
|
@@ -4,10 +4,18 @@ export interface DogfoodAccessSnapshot {
|
|
|
4
4
|
yaverAuthenticated: boolean;
|
|
5
5
|
/** Backend-confirmed owner/maintainer of this exact appId. */
|
|
6
6
|
ownerAuthorized: boolean;
|
|
7
|
+
/** Backend-confirmed app assignment for this Yaver account. App owners are
|
|
8
|
+
* assigned implicitly; other accounts require an active owner grant. */
|
|
9
|
+
accountAuthorized: boolean;
|
|
7
10
|
installationId?: string;
|
|
8
11
|
deviceState: 'unknown' | 'unregistered' | 'pending' | 'active' | 'cancelled' | 'revoked' | 'superseded';
|
|
9
|
-
/** True only for
|
|
12
|
+
/** True only for an assigned account and this backend-approved device key. */
|
|
10
13
|
authorized: boolean;
|
|
14
|
+
/** OAuth-backed preference scoped to this user + app + installation. */
|
|
15
|
+
controlPresentation?: 'auto' | 'minimized-y';
|
|
16
|
+
gestureSupported?: boolean;
|
|
17
|
+
gestureCapabilityReason?: string;
|
|
18
|
+
controlOnboardingSeen?: boolean;
|
|
11
19
|
}
|
|
12
20
|
|
|
13
21
|
export interface DogfoodFlowSnapshot {
|
|
@@ -44,6 +52,19 @@ export interface SDKDogfoodConfig {
|
|
|
44
52
|
/** ACL-backed Home Screen/App Shortcut. Dynamic and absent until Yaver
|
|
45
53
|
* owner auth or this installation's approved key authorizes it. */
|
|
46
54
|
appShortcut?: boolean | { label?: string };
|
|
55
|
+
/** Smart in-app quick controls. On supported standalone iOS/Android builds,
|
|
56
|
+
* a three-finger hold opens a two-action card with no persistent overlay.
|
|
57
|
+
* Unsupported/accessibility-conflicted devices may show a minimized,
|
|
58
|
+
* draggable Y fallback. Yaver host/container mode suppresses both. */
|
|
59
|
+
controlGesture?: boolean | {
|
|
60
|
+
/** Hold duration, clamped to 650–2000 ms. Default 900 ms. */
|
|
61
|
+
durationMs?: number;
|
|
62
|
+
/** Default `minimized-y`; use `none` when Settings is the only fallback. */
|
|
63
|
+
fallback?: 'minimized-y' | 'none';
|
|
64
|
+
/** Initial user-facing presentation before their persisted SDK preference
|
|
65
|
+
* exists. `auto` keeps pixels clear when the gesture works. */
|
|
66
|
+
defaultPresentation?: 'auto' | 'minimized-y';
|
|
67
|
+
};
|
|
47
68
|
}
|
|
48
69
|
|
|
49
70
|
export interface SDKDogfoodStatus {
|
package/src/index.ts
CHANGED
|
@@ -29,7 +29,12 @@
|
|
|
29
29
|
*/
|
|
30
30
|
|
|
31
31
|
export { YaverFeedback } from './YaverFeedback';
|
|
32
|
-
export type {
|
|
32
|
+
export type {
|
|
33
|
+
DogfoodOnboardingOptions,
|
|
34
|
+
DogfoodFlowPhase,
|
|
35
|
+
DogfoodFlowState,
|
|
36
|
+
DogfoodControlTriggerState,
|
|
37
|
+
} from './YaverFeedback';
|
|
33
38
|
export { captureStoreScreenshots } from './storeShots';
|
|
34
39
|
export type {
|
|
35
40
|
CaptureStoreScreenshotsOptions,
|
|
@@ -106,7 +111,14 @@ export type {
|
|
|
106
111
|
DogfoodRunContext,
|
|
107
112
|
DogfoodSnapshot,
|
|
108
113
|
} from './DogfoodRuntime';
|
|
114
|
+
export { DogfoodLanePicker, DogfoodLiveConsole, DogfoodStatusRail } from './DogfoodSessionUi';
|
|
115
|
+
export type {
|
|
116
|
+
DogfoodStatusStep,
|
|
117
|
+
DogfoodStatusTone,
|
|
118
|
+
DogfoodUiColors,
|
|
119
|
+
} from './DogfoodSessionUi';
|
|
109
120
|
export { FeedbackModal } from './FeedbackModal';
|
|
121
|
+
export { DogfoodQuickControls } from './DogfoodQuickControls';
|
|
110
122
|
export { QuickActionIcon } from './QuickActionIcon';
|
|
111
123
|
export type { QuickActionIconProps } from './QuickActionIcon';
|
|
112
124
|
export { FixReport } from './FixReport';
|
package/src/preferences.ts
CHANGED
|
@@ -26,6 +26,95 @@ try {
|
|
|
26
26
|
|
|
27
27
|
const QUICK_ICON_DISABLED_KEY = 'yaver_feedback_quickicon_disabled';
|
|
28
28
|
const QUICK_ICON_COLOR_KEY = 'yaver_feedback_quickicon_color';
|
|
29
|
+
const DOGFOOD_CONTROL_PRESENTATION_KEY = 'yaver_dogfood_control_presentation';
|
|
30
|
+
const DOGFOOD_CONTROL_POSITION_PREFIX = 'yaver_dogfood_control_position_';
|
|
31
|
+
const DOGFOOD_CONTROL_ONBOARDING_PREFIX = 'yaver_dogfood_control_onboarding_';
|
|
32
|
+
|
|
33
|
+
export type DogfoodControlPresentation = 'auto' | 'minimized-y';
|
|
34
|
+
export type DogfoodControlEdge = 'left' | 'right';
|
|
35
|
+
export interface DogfoodControlPosition {
|
|
36
|
+
edge: DogfoodControlEdge;
|
|
37
|
+
/** 0–1 within the safe vertical travel area. */
|
|
38
|
+
yRatio: number;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function dogfoodPreferenceKey(base: string, scope?: string): string {
|
|
42
|
+
const normalized = String(scope || 'legacy').trim() || 'legacy';
|
|
43
|
+
return `${base}_${encodeURIComponent(normalized)}`;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export async function getDogfoodControlPresentation(scope?: string): Promise<DogfoodControlPresentation | null> {
|
|
47
|
+
if (!AsyncStorage) return null;
|
|
48
|
+
try {
|
|
49
|
+
const value = await AsyncStorage.getItem(dogfoodPreferenceKey(DOGFOOD_CONTROL_PRESENTATION_KEY, scope));
|
|
50
|
+
return value === 'auto' || value === 'minimized-y' ? value : null;
|
|
51
|
+
} catch {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export async function setDogfoodControlPresentation(value: DogfoodControlPresentation, scope?: string): Promise<void> {
|
|
57
|
+
if (!AsyncStorage) return;
|
|
58
|
+
try {
|
|
59
|
+
await AsyncStorage.setItem(dogfoodPreferenceKey(DOGFOOD_CONTROL_PRESENTATION_KEY, scope), value);
|
|
60
|
+
} catch {
|
|
61
|
+
// best-effort
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export async function getDogfoodControlPosition(
|
|
66
|
+
orientation: 'portrait' | 'landscape',
|
|
67
|
+
scope?: string,
|
|
68
|
+
): Promise<DogfoodControlPosition | null> {
|
|
69
|
+
if (!AsyncStorage) return null;
|
|
70
|
+
try {
|
|
71
|
+
const raw = await AsyncStorage.getItem(
|
|
72
|
+
dogfoodPreferenceKey(`${DOGFOOD_CONTROL_POSITION_PREFIX}${orientation}`, scope),
|
|
73
|
+
);
|
|
74
|
+
if (!raw) return null;
|
|
75
|
+
const parsed = JSON.parse(raw) as Partial<DogfoodControlPosition>;
|
|
76
|
+
if ((parsed.edge !== 'left' && parsed.edge !== 'right') || typeof parsed.yRatio !== 'number') return null;
|
|
77
|
+
return { edge: parsed.edge, yRatio: Math.max(0, Math.min(1, parsed.yRatio)) };
|
|
78
|
+
} catch {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export async function setDogfoodControlPosition(
|
|
84
|
+
orientation: 'portrait' | 'landscape',
|
|
85
|
+
position: DogfoodControlPosition,
|
|
86
|
+
scope?: string,
|
|
87
|
+
): Promise<void> {
|
|
88
|
+
if (!AsyncStorage) return;
|
|
89
|
+
try {
|
|
90
|
+
await AsyncStorage.setItem(
|
|
91
|
+
dogfoodPreferenceKey(`${DOGFOOD_CONTROL_POSITION_PREFIX}${orientation}`, scope),
|
|
92
|
+
JSON.stringify(position),
|
|
93
|
+
);
|
|
94
|
+
} catch {
|
|
95
|
+
// best-effort
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export async function getDogfoodControlOnboardingSeen(scope?: string): Promise<boolean> {
|
|
100
|
+
if (!AsyncStorage) return false;
|
|
101
|
+
try {
|
|
102
|
+
return await AsyncStorage.getItem(dogfoodPreferenceKey(DOGFOOD_CONTROL_ONBOARDING_PREFIX, scope)) === '1';
|
|
103
|
+
} catch {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export async function setDogfoodControlOnboardingSeen(seen: boolean, scope?: string): Promise<void> {
|
|
109
|
+
if (!AsyncStorage) return;
|
|
110
|
+
try {
|
|
111
|
+
const key = dogfoodPreferenceKey(DOGFOOD_CONTROL_ONBOARDING_PREFIX, scope);
|
|
112
|
+
if (seen) await AsyncStorage.setItem(key, '1');
|
|
113
|
+
else await AsyncStorage.removeItem(key);
|
|
114
|
+
} catch {
|
|
115
|
+
// best-effort startup cache; Convex remains authoritative.
|
|
116
|
+
}
|
|
117
|
+
}
|
|
29
118
|
|
|
30
119
|
export type QuickIconColorPreset =
|
|
31
120
|
| 'orange'
|