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/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
 
@@ -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 a backend-approved device key or an authenticated owner. */
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 { DogfoodOnboardingOptions, DogfoodFlowPhase, DogfoodFlowState } from './YaverFeedback';
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';
@@ -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'