yaver-feedback-react-native 0.8.8 → 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.
@@ -13,10 +13,13 @@ const preferences_1 = require("./preferences");
13
13
  // (mobile/ios/Yaver/YaverInfo.{swift,m} + Android counterpart); a
14
14
  // standalone app bundled by its own developer has no such module.
15
15
  // When the SDK is loaded through Yaver's Hermes-push guest runtime we
16
- // deliberately no-op every public entry point Yaver owns the shake
17
- // gesture ("Reload / Back to Yaver" overlay), the feedback capture
18
- // flow, and the BlackBox streaming; running a second copy from inside
19
- // the guest just produces duplicate UIs and double P2P sessions.
16
+ // run in HOST MODE: dormant by default (no shake detector, no auto
17
+ // BlackBox, no QuickActionIcon Yaver's host shell owns those), but
18
+ // we DO register a DeviceEventEmitter listener so Yaver's overlay can
19
+ // flip the SDK live at runtime. When the user shakes inside the guest
20
+ // app and taps "Feedback" on the Yaver overlay, AppDelegate dispatches
21
+ // `yaverFeedback:startReport` into this bridge; the listener wakes the
22
+ // SDK and opens the modal in-place over the running guest UI.
20
23
  function isRunningInsideYaverHost() {
21
24
  try {
22
25
  return !!react_native_1.NativeModules?.YaverInfo;
@@ -25,11 +28,108 @@ function isRunningInsideYaverHost() {
25
28
  return false;
26
29
  }
27
30
  }
28
- // Suppresses SDK activation when inside Yaver super-host. Callers of
29
- // YaverFeedback.init / startReport / startBatchRecording / … early-out
30
- // by checking this first so the SDK's side effects (accelerometer,
31
- // BlackBox HTTP, SSE command channel, FeedbackModal mount) never start.
32
- const YAVER_HOST_SUPPRESS = isRunningInsideYaverHost();
31
+ // Two distinct compile-time modes for a guest app like sfmg / talos:
32
+ //
33
+ // YAVER_HOST_MODE — bundled by Yaver's agent (/dev/build-native) for
34
+ // loading inside Yaver mobile. SDK code is in the
35
+ // bundle but boots PASSIVE: no shake detector, no
36
+ // auto-BlackBox, no container UI. Yaver's host
37
+ // overlay owns the shake gesture; when the user
38
+ // taps "Feedback" on Yaver's overlay, AppDelegate
39
+ // dispatches yaverFeedback:hostActivate into this
40
+ // bridge and the SDK runtime-flips active for a
41
+ // single feedback session.
42
+ //
43
+ // YAVER_SDK_MODE — sfmg's own standalone TestFlight / Play Store
44
+ // build, with the Yaver SDK embedded. SDK boots
45
+ // active: shake → modal directly, no Yaver host
46
+ // involved. Default for normal `expo build`.
47
+ //
48
+ // Both can be forced at build time via process.env. When neither is
49
+ // set, fall back to runtime detection: if the YaverInfo native module
50
+ // exists (we're inside Yaver), assume HOST_MODE; else SDK_MODE. This
51
+ // keeps older bundles (built before the agent learned to set the env)
52
+ // working unchanged.
53
+ const YAVER_HOST_MODE_BUILD = (() => {
54
+ try {
55
+ const v = process.env?.YAVER_HOST_MODE;
56
+ return v === 'true' || v === '1' || v === true || v === 1;
57
+ }
58
+ catch {
59
+ return false;
60
+ }
61
+ })();
62
+ const YAVER_SDK_MODE_BUILD = (() => {
63
+ try {
64
+ const v = process.env?.YAVER_SDK_MODE;
65
+ return v === 'true' || v === '1' || v === true || v === 1;
66
+ }
67
+ catch {
68
+ return false;
69
+ }
70
+ })();
71
+ // Effective mode after considering build flags AND runtime detection.
72
+ const IS_HOST_MODE = YAVER_HOST_MODE_BUILD ||
73
+ (!YAVER_SDK_MODE_BUILD && isRunningInsideYaverHost());
74
+ // Tracks whether we've been runtime-activated by the host (sfmg-in-Yaver
75
+ // case). Independent of `enabled` so we can tell "host turned us on for
76
+ // one shot" apart from "developer toggled enabled programmatically".
77
+ let hostActivated = false;
78
+ // Host-activation listener. Always registered when in HOST mode so a
79
+ // Yaver overlay tap can wake the SDK even before the guest's
80
+ // YaverFeedback.init() runs. AppDelegate (mobile/ios/Yaver/AppDelegate.
81
+ // swift::handleFeedbackTap) sends `yaverFeedback:startReport` into the
82
+ // guest bridge when the user picks Feedback on the shake overlay.
83
+ //
84
+ // Activation flow:
85
+ // 1. Try Yaver's existing bearer (NativeModules.YaverInfo.
86
+ // inheritedAuthToken, populated by Yaver mobile's auth.ts on
87
+ // sign-in). Validate against /auth/validate before trusting.
88
+ // 2. If valid: setAuthToken + open feedback modal in-place (the
89
+ // modal already supports hot reload, screenshot, vibing chat).
90
+ // 3. If missing or invalid: open the SDK's own login screen.
91
+ if (IS_HOST_MODE) {
92
+ try {
93
+ const { DeviceEventEmitter } = require('react-native');
94
+ DeviceEventEmitter.addListener('yaverFeedback:startReport', () => {
95
+ hostActivated = true;
96
+ enabled = true;
97
+ void (async () => {
98
+ const yi = react_native_1.NativeModules?.YaverInfo;
99
+ const inheritedToken = String(yi?.inheritedAuthToken || '').trim();
100
+ const inheritedAgent = String(yi?.inheritedAgentUrl || '').trim();
101
+ const inheritedDevice = String(yi?.inheritedDeviceId || '').trim();
102
+ if (inheritedToken) {
103
+ // Lazy-import auth.ts so module load doesn't drag the auth
104
+ // network code into the active set when the SDK is dormant.
105
+ const { validateToken } = require('./auth');
106
+ const user = await validateToken(inheritedToken).catch(() => null);
107
+ if (user) {
108
+ // Seed config + connect the SDK to the host's auth.
109
+ if (!config) {
110
+ YaverFeedback.init({
111
+ authToken: inheritedToken,
112
+ agentUrl: inheritedAgent || undefined,
113
+ preferredDeviceId: inheritedDevice || undefined,
114
+ });
115
+ }
116
+ await YaverFeedback.setAuthToken(inheritedToken);
117
+ await YaverFeedback.startReport();
118
+ return;
119
+ }
120
+ }
121
+ // No token, or token invalid — fall through to the SDK's own
122
+ // login screen. The user picks an OAuth provider; on success
123
+ // the modal continues with the new token.
124
+ if (!config) {
125
+ YaverFeedback.init({});
126
+ }
127
+ YaverFeedback.showLogin();
128
+ })();
129
+ });
130
+ }
131
+ catch { /* react-native unavailable in jsdom unit tests */ }
132
+ }
33
133
  let config = null;
34
134
  let enabled = false;
35
135
  let p2pClient = null;
@@ -102,17 +202,34 @@ class YaverFeedback {
102
202
  * via `YaverDiscovery` on the first `startReport()` call.
103
203
  */
104
204
  static init(cfg) {
105
- if (YAVER_HOST_SUPPRESS) {
106
- // Running inside Yaver's super-host — yield to Yaver's native UX.
107
- enabled = false;
108
- return;
109
- }
110
205
  config = {
111
206
  trigger: 'shake',
112
207
  maxRecordingDuration: 120,
113
208
  autoLogin: true,
114
209
  ...cfg,
115
210
  };
211
+ if (IS_HOST_MODE) {
212
+ // sfmg / talos / etc. running inside Yaver mobile (compile-time
213
+ // YAVER_HOST_MODE or runtime-detected). Store config so a later
214
+ // host activation (yaverFeedback:startReport from AppDelegate)
215
+ // can open the modal — but skip the side effects Yaver's host
216
+ // shell owns: shake detector, auto-BlackBox, QuickActionIcon.
217
+ enabled = false;
218
+ // Configure auth endpoints + strict-native-auth even in passive
219
+ // mode so a host-activated session uses the same login routing
220
+ // the standalone path would.
221
+ (0, auth_1.configureAuthEndpoints)({
222
+ convexSiteUrl: cfg.authConvexSiteUrl,
223
+ webBaseUrl: cfg.authWebBaseUrl,
224
+ });
225
+ (0, auth_1.setStrictNativeAuth)(cfg.strictNativeAuth === true);
226
+ if (!config.convexUrl) {
227
+ config.convexUrl = cfg.authConvexSiteUrl ?? auth_1.DEFAULT_CONVEX_SITE_URL;
228
+ }
229
+ maxErrors = cfg.maxCapturedErrors ?? 5;
230
+ errorBuffer = [];
231
+ return;
232
+ }
116
233
  if (config.disableShakeGesture && (!config.quickIcon || config.quickIcon === 'auto')) {
117
234
  config.quickIcon = 'always';
118
235
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yaver-feedback-react-native",
3
- "version": "0.8.8",
3
+ "version": "0.8.9",
4
4
  "description": "Visual feedback SDK for Yaver \u2014 bug reports, screen recording, voice annotations, and local-first developer workflows",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -28,10 +28,13 @@ import {
28
28
  // (mobile/ios/Yaver/YaverInfo.{swift,m} + Android counterpart); a
29
29
  // standalone app bundled by its own developer has no such module.
30
30
  // When the SDK is loaded through Yaver's Hermes-push guest runtime we
31
- // deliberately no-op every public entry point Yaver owns the shake
32
- // gesture ("Reload / Back to Yaver" overlay), the feedback capture
33
- // flow, and the BlackBox streaming; running a second copy from inside
34
- // the guest just produces duplicate UIs and double P2P sessions.
31
+ // run in HOST MODE: dormant by default (no shake detector, no auto
32
+ // BlackBox, no QuickActionIcon Yaver's host shell owns those), but
33
+ // we DO register a DeviceEventEmitter listener so Yaver's overlay can
34
+ // flip the SDK live at runtime. When the user shakes inside the guest
35
+ // app and taps "Feedback" on the Yaver overlay, AppDelegate dispatches
36
+ // `yaverFeedback:startReport` into this bridge; the listener wakes the
37
+ // SDK and opens the modal in-place over the running guest UI.
35
38
  function isRunningInsideYaverHost(): boolean {
36
39
  try {
37
40
  return !!(NativeModules as any)?.YaverInfo;
@@ -40,11 +43,105 @@ function isRunningInsideYaverHost(): boolean {
40
43
  }
41
44
  }
42
45
 
43
- // Suppresses SDK activation when inside Yaver super-host. Callers of
44
- // YaverFeedback.init / startReport / startBatchRecording / … early-out
45
- // by checking this first so the SDK's side effects (accelerometer,
46
- // BlackBox HTTP, SSE command channel, FeedbackModal mount) never start.
47
- const YAVER_HOST_SUPPRESS = isRunningInsideYaverHost();
46
+ // Two distinct compile-time modes for a guest app like sfmg / talos:
47
+ //
48
+ // YAVER_HOST_MODE — bundled by Yaver's agent (/dev/build-native) for
49
+ // loading inside Yaver mobile. SDK code is in the
50
+ // bundle but boots PASSIVE: no shake detector, no
51
+ // auto-BlackBox, no container UI. Yaver's host
52
+ // overlay owns the shake gesture; when the user
53
+ // taps "Feedback" on Yaver's overlay, AppDelegate
54
+ // dispatches yaverFeedback:hostActivate into this
55
+ // bridge and the SDK runtime-flips active for a
56
+ // single feedback session.
57
+ //
58
+ // YAVER_SDK_MODE — sfmg's own standalone TestFlight / Play Store
59
+ // build, with the Yaver SDK embedded. SDK boots
60
+ // active: shake → modal directly, no Yaver host
61
+ // involved. Default for normal `expo build`.
62
+ //
63
+ // Both can be forced at build time via process.env. When neither is
64
+ // set, fall back to runtime detection: if the YaverInfo native module
65
+ // exists (we're inside Yaver), assume HOST_MODE; else SDK_MODE. This
66
+ // keeps older bundles (built before the agent learned to set the env)
67
+ // working unchanged.
68
+ const YAVER_HOST_MODE_BUILD = (() => {
69
+ try {
70
+ const v = (process.env as any)?.YAVER_HOST_MODE;
71
+ return v === 'true' || v === '1' || v === true || v === 1;
72
+ } catch { return false; }
73
+ })();
74
+ const YAVER_SDK_MODE_BUILD = (() => {
75
+ try {
76
+ const v = (process.env as any)?.YAVER_SDK_MODE;
77
+ return v === 'true' || v === '1' || v === true || v === 1;
78
+ } catch { return false; }
79
+ })();
80
+
81
+ // Effective mode after considering build flags AND runtime detection.
82
+ const IS_HOST_MODE =
83
+ YAVER_HOST_MODE_BUILD ||
84
+ (!YAVER_SDK_MODE_BUILD && isRunningInsideYaverHost());
85
+
86
+ // Tracks whether we've been runtime-activated by the host (sfmg-in-Yaver
87
+ // case). Independent of `enabled` so we can tell "host turned us on for
88
+ // one shot" apart from "developer toggled enabled programmatically".
89
+ let hostActivated = false;
90
+
91
+ // Host-activation listener. Always registered when in HOST mode so a
92
+ // Yaver overlay tap can wake the SDK even before the guest's
93
+ // YaverFeedback.init() runs. AppDelegate (mobile/ios/Yaver/AppDelegate.
94
+ // swift::handleFeedbackTap) sends `yaverFeedback:startReport` into the
95
+ // guest bridge when the user picks Feedback on the shake overlay.
96
+ //
97
+ // Activation flow:
98
+ // 1. Try Yaver's existing bearer (NativeModules.YaverInfo.
99
+ // inheritedAuthToken, populated by Yaver mobile's auth.ts on
100
+ // sign-in). Validate against /auth/validate before trusting.
101
+ // 2. If valid: setAuthToken + open feedback modal in-place (the
102
+ // modal already supports hot reload, screenshot, vibing chat).
103
+ // 3. If missing or invalid: open the SDK's own login screen.
104
+ if (IS_HOST_MODE) {
105
+ try {
106
+ const { DeviceEventEmitter } = require('react-native');
107
+ DeviceEventEmitter.addListener('yaverFeedback:startReport', () => {
108
+ hostActivated = true;
109
+ enabled = true;
110
+ void (async () => {
111
+ const yi = (NativeModules as any)?.YaverInfo;
112
+ const inheritedToken = String(yi?.inheritedAuthToken || '').trim();
113
+ const inheritedAgent = String(yi?.inheritedAgentUrl || '').trim();
114
+ const inheritedDevice = String(yi?.inheritedDeviceId || '').trim();
115
+ if (inheritedToken) {
116
+ // Lazy-import auth.ts so module load doesn't drag the auth
117
+ // network code into the active set when the SDK is dormant.
118
+ const { validateToken } = require('./auth');
119
+ const user = await validateToken(inheritedToken).catch(() => null);
120
+ if (user) {
121
+ // Seed config + connect the SDK to the host's auth.
122
+ if (!config) {
123
+ YaverFeedback.init({
124
+ authToken: inheritedToken,
125
+ agentUrl: inheritedAgent || undefined,
126
+ preferredDeviceId: inheritedDevice || undefined,
127
+ } as FeedbackConfig);
128
+ }
129
+ await YaverFeedback.setAuthToken(inheritedToken);
130
+ await YaverFeedback.startReport();
131
+ return;
132
+ }
133
+ }
134
+ // No token, or token invalid — fall through to the SDK's own
135
+ // login screen. The user picks an OAuth provider; on success
136
+ // the modal continues with the new token.
137
+ if (!config) {
138
+ YaverFeedback.init({} as FeedbackConfig);
139
+ }
140
+ YaverFeedback.showLogin();
141
+ })();
142
+ });
143
+ } catch { /* react-native unavailable in jsdom unit tests */ }
144
+ }
48
145
 
49
146
  let config: FeedbackConfig | null = null;
50
147
  let enabled = false;
@@ -126,17 +223,34 @@ export class YaverFeedback {
126
223
  * via `YaverDiscovery` on the first `startReport()` call.
127
224
  */
128
225
  static init(cfg: FeedbackConfig): void {
129
- if (YAVER_HOST_SUPPRESS) {
130
- // Running inside Yaver's super-host — yield to Yaver's native UX.
131
- enabled = false;
132
- return;
133
- }
134
226
  config = {
135
227
  trigger: 'shake',
136
228
  maxRecordingDuration: 120,
137
229
  autoLogin: true,
138
230
  ...cfg,
139
231
  };
232
+ if (IS_HOST_MODE) {
233
+ // sfmg / talos / etc. running inside Yaver mobile (compile-time
234
+ // YAVER_HOST_MODE or runtime-detected). Store config so a later
235
+ // host activation (yaverFeedback:startReport from AppDelegate)
236
+ // can open the modal — but skip the side effects Yaver's host
237
+ // shell owns: shake detector, auto-BlackBox, QuickActionIcon.
238
+ enabled = false;
239
+ // Configure auth endpoints + strict-native-auth even in passive
240
+ // mode so a host-activated session uses the same login routing
241
+ // the standalone path would.
242
+ configureAuthEndpoints({
243
+ convexSiteUrl: cfg.authConvexSiteUrl,
244
+ webBaseUrl: cfg.authWebBaseUrl,
245
+ });
246
+ setStrictNativeAuth(cfg.strictNativeAuth === true);
247
+ if (!config.convexUrl) {
248
+ config.convexUrl = cfg.authConvexSiteUrl ?? DEFAULT_CONVEX_SITE_URL;
249
+ }
250
+ maxErrors = cfg.maxCapturedErrors ?? 5;
251
+ errorBuffer = [];
252
+ return;
253
+ }
140
254
  if (config.disableShakeGesture && (!config.quickIcon || config.quickIcon === 'auto')) {
141
255
  config.quickIcon = 'always';
142
256
  }