yaver-feedback-react-native 0.9.0 → 0.9.3
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 +102 -1
- package/app.plugin.js +126 -9
- package/dist/AuthOverlay.d.ts +1 -14
- package/dist/AuthOverlay.js +9 -62
- package/dist/BlackBox.js +9 -1
- package/dist/DeployPanel.js +65 -0
- package/dist/Discovery.js +13 -8
- package/dist/DogfoodRuntime.d.ts +124 -0
- package/dist/DogfoodRuntime.js +273 -0
- package/dist/FeedbackModal.js +505 -65
- package/dist/LoginScreen.d.ts +1 -5
- package/dist/LoginScreen.js +2 -6
- package/dist/MachinePickerScreen.d.ts +1 -3
- package/dist/MachinePickerScreen.js +6 -18
- package/dist/P2PClient.d.ts +178 -2
- package/dist/P2PClient.js +493 -3
- package/dist/P2PDogfoodDriver.d.ts +12 -0
- package/dist/P2PDogfoodDriver.js +118 -0
- package/dist/PairDeviceModal.d.ts +2 -3
- package/dist/ShakeDetector.js +2 -0
- package/dist/VibeChatScreen.d.ts +11 -1
- package/dist/VibeChatScreen.js +200 -41
- package/dist/YaverFeedback.d.ts +132 -0
- package/dist/YaverFeedback.js +633 -65
- package/dist/YaverModeBadge.d.ts +22 -0
- package/dist/YaverModeBadge.js +219 -0
- package/dist/__tests__/AuthDevices.test.js +1 -48
- package/dist/__tests__/BlackBox.relayPassword.test.d.ts +1 -0
- package/dist/__tests__/BlackBox.relayPassword.test.js +105 -0
- package/dist/__tests__/BlackBoxAutoStart.test.d.ts +1 -0
- package/dist/__tests__/BlackBoxAutoStart.test.js +91 -0
- package/dist/__tests__/BlackBoxAutoStartColdStart.test.d.ts +1 -0
- package/dist/__tests__/BlackBoxAutoStartColdStart.test.js +156 -0
- package/dist/__tests__/BrowserLaneIcon.test.d.ts +3 -0
- package/dist/__tests__/BrowserLaneIcon.test.js +80 -0
- package/dist/__tests__/DogfoodRuntime.test.d.ts +1 -0
- package/dist/__tests__/DogfoodRuntime.test.js +116 -0
- package/dist/__tests__/P2PClient.test.js +2 -2
- package/dist/__tests__/P2PDogfoodDriver.test.d.ts +1 -0
- package/dist/__tests__/P2PDogfoodDriver.test.js +64 -0
- package/dist/__tests__/ReportIdentity.test.d.ts +25 -0
- package/dist/__tests__/ReportIdentity.test.js +180 -0
- package/dist/__tests__/SDKToken.test.js +1 -1
- package/dist/__tests__/ShakeToggle.test.d.ts +1 -0
- package/dist/__tests__/ShakeToggle.test.js +121 -0
- package/dist/__tests__/YaverFeedback.test.js +13 -3
- package/dist/__tests__/deviceDogfood.test.d.ts +1 -0
- package/dist/__tests__/deviceDogfood.test.js +86 -0
- package/dist/__tests__/dogfoodPolicy.test.d.ts +1 -0
- package/dist/__tests__/dogfoodPolicy.test.js +33 -0
- package/dist/__tests__/pickTargetDevice.test.d.ts +1 -0
- package/dist/__tests__/pickTargetDevice.test.js +89 -0
- package/dist/__tests__/reloadActions.test.d.ts +1 -0
- package/dist/__tests__/reloadActions.test.js +129 -0
- package/dist/__tests__/reloadActionsParity.test.d.ts +1 -0
- package/dist/__tests__/reloadActionsParity.test.js +42 -0
- package/dist/__tests__/types.test.js +5 -5
- package/dist/_core/ansi.d.ts +117 -0
- package/dist/_core/ansi.js +468 -0
- package/dist/_core/ansi.test.d.ts +1 -0
- package/dist/_core/ansi.test.js +225 -0
- package/dist/_core/buildFeedbackPrompt.d.ts +4 -9
- package/dist/_core/buildFeedbackPrompt.js +18 -72
- package/dist/_core/constants.d.ts +19 -6
- package/dist/_core/constants.js +20 -7
- package/dist/_core/device.d.ts +1 -5
- package/dist/_core/device.js +5 -14
- package/dist/_core/endpoints.d.ts +0 -7
- package/dist/_core/endpoints.js +0 -7
- package/dist/_core/index.d.ts +4 -0
- package/dist/_core/index.js +4 -0
- package/dist/_core/remoteless.d.ts +44 -0
- package/dist/_core/remoteless.js +75 -0
- package/dist/_core/trace.d.ts +47 -0
- package/dist/_core/trace.js +38 -0
- package/dist/_core/trace.test.d.ts +1 -0
- package/dist/_core/trace.test.js +60 -0
- package/dist/auth.d.ts +3 -60
- package/dist/auth.js +6 -88
- package/dist/deviceDogfood.d.ts +53 -0
- package/dist/deviceDogfood.js +137 -0
- package/dist/dogfoodPolicy.d.ts +25 -0
- package/dist/dogfoodPolicy.js +24 -0
- package/dist/index.d.ts +17 -4
- package/dist/index.js +33 -7
- package/dist/reloadActions.d.ts +88 -0
- package/dist/reloadActions.js +200 -0
- package/dist/storeShots.d.ts +67 -0
- package/dist/storeShots.js +137 -0
- package/dist/types.d.ts +208 -8
- package/package.json +13 -4
- package/src/AuthOverlay.tsx +20 -106
- package/src/BlackBox.ts +10 -1
- package/src/DeployPanel.tsx +74 -0
- package/src/Discovery.ts +13 -8
- package/src/DogfoodRuntime.ts +373 -0
- package/src/FeedbackModal.tsx +619 -79
- package/src/LoginScreen.tsx +2 -22
- package/src/MachinePickerScreen.tsx +6 -21
- package/src/P2PClient.ts +580 -4
- package/src/P2PDogfoodDriver.ts +132 -0
- package/src/PairDeviceModal.tsx +2 -3
- package/src/ShakeDetector.ts +1 -0
- package/src/VibeChatScreen.tsx +232 -42
- package/src/YaverFeedback.ts +631 -68
- package/src/YaverModeBadge.tsx +234 -0
- package/src/__tests__/AuthDevices.test.ts +1 -52
- package/src/__tests__/BlackBox.relayPassword.test.ts +129 -0
- package/src/__tests__/BlackBoxAutoStart.test.ts +111 -0
- package/src/__tests__/BlackBoxAutoStartColdStart.test.ts +191 -0
- package/src/__tests__/BrowserLaneIcon.test.ts +85 -0
- package/src/__tests__/DogfoodRuntime.test.ts +135 -0
- package/src/__tests__/P2PClient.test.ts +2 -2
- package/src/__tests__/P2PDogfoodDriver.test.ts +80 -0
- package/src/__tests__/ReportIdentity.test.ts +212 -0
- package/src/__tests__/SDKToken.test.ts +1 -1
- package/src/__tests__/ShakeToggle.test.ts +153 -0
- package/src/__tests__/YaverFeedback.test.ts +15 -3
- package/src/__tests__/deviceDogfood.test.ts +77 -0
- package/src/__tests__/dogfoodPolicy.test.ts +34 -0
- package/src/__tests__/pickTargetDevice.test.ts +101 -0
- package/src/__tests__/reloadActions.test.ts +171 -0
- package/src/__tests__/reloadActionsParity.test.ts +49 -0
- package/src/__tests__/types.test.ts +5 -5
- package/src/_core/ansi.test.ts +250 -0
- package/src/_core/ansi.ts +475 -0
- package/src/_core/buildFeedbackPrompt.ts +18 -95
- package/src/_core/constants.ts +20 -6
- package/src/_core/device.ts +5 -16
- package/src/_core/endpoints.ts +0 -7
- package/src/_core/index.ts +4 -0
- package/src/_core/remoteless.ts +110 -0
- package/src/_core/trace.test.ts +58 -0
- package/src/_core/trace.ts +75 -0
- package/src/auth.ts +7 -156
- package/src/deviceDogfood.ts +171 -0
- package/src/dogfoodPolicy.ts +40 -0
- package/src/index.ts +61 -11
- package/src/reloadActions.ts +273 -0
- package/src/storeShots.ts +189 -0
- package/src/types.ts +209 -8
- package/dist/GuestOnboardingScreen.d.ts +0 -8
- package/dist/GuestOnboardingScreen.js +0 -282
- package/src/GuestOnboardingScreen.tsx +0 -307
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
/** Hide the mark for the rest of this run. Exposed on YaverFeedback so a host
|
|
3
|
+
* can wire its own "hide" control, and used by the sheet's own button. */
|
|
4
|
+
export declare function hideYaverModeBadge(): void;
|
|
5
|
+
/** Bring it back — e.g. when a NEW guest bundle loads and the context changed. */
|
|
6
|
+
export declare function showYaverModeBadge(): void;
|
|
7
|
+
export declare function isYaverModeBadgeHidden(): boolean;
|
|
8
|
+
export interface YaverModeBadgeProps {
|
|
9
|
+
/** Corner to sit in. Default bottom-left: bottom-right is where most apps
|
|
10
|
+
* put a FAB, and the badge must never compete with the app's own action. */
|
|
11
|
+
position?: 'bottom-left' | 'bottom-right' | 'top-left' | 'top-right';
|
|
12
|
+
/** Render even outside Yaver. Development aid only — the badge is meaningless
|
|
13
|
+
* in a standalone build and would be wallpaper. */
|
|
14
|
+
force?: boolean;
|
|
15
|
+
/** Account-scoped third-party Dogfood mode. Keeps the same Yaver Y mark but
|
|
16
|
+
* changes the explanation and offers a confirmed exit to normal Feedback. */
|
|
17
|
+
dogfood?: boolean;
|
|
18
|
+
dogfoodLabel?: string;
|
|
19
|
+
onExitDogfood?: () => void | Promise<void>;
|
|
20
|
+
}
|
|
21
|
+
export declare function YaverModeBadge({ position, force, dogfood, dogfoodLabel, onExitDogfood, }: YaverModeBadgeProps): React.JSX.Element | null;
|
|
22
|
+
export default YaverModeBadge;
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// YaverModeBadge.tsx — the polite "you're running inside Yaver" mark, for
|
|
3
|
+
// THIRD-PARTY apps.
|
|
4
|
+
//
|
|
5
|
+
// ── Why a third-party app needs this ────────────────────────────────────────
|
|
6
|
+
//
|
|
7
|
+
// When your app is pushed into Yaver's container as a Hermes bundle, it looks
|
|
8
|
+
// exactly like your installed build. Same icon, same launch, same everything —
|
|
9
|
+
// except it is a development bundle from someone's branch. Testers have chased
|
|
10
|
+
// "bugs" that were only unbuilt work, and have been unable to find their way
|
|
11
|
+
// back to the real app because nothing on screen said there was anywhere to go.
|
|
12
|
+
//
|
|
13
|
+
// So the SDK shows one small Y, low contrast, in a corner. Tapping it says what
|
|
14
|
+
// you're in and how to leave. Nothing else.
|
|
15
|
+
//
|
|
16
|
+
// ── Defaults, and why ───────────────────────────────────────────────────────
|
|
17
|
+
//
|
|
18
|
+
// DEFAULT ENABLED (`modeBadge: true`), because the failure it prevents is
|
|
19
|
+
// silent and lands on a tester rather than the developer — exactly the class
|
|
20
|
+
// that should not be opt-in. Turn it off with `modeBadge: false` when your app
|
|
21
|
+
// has its own in-container indicator, or when a screenshot-perfect surface
|
|
22
|
+
// genuinely cannot afford 22 points in a corner.
|
|
23
|
+
//
|
|
24
|
+
// ── What it is NOT ──────────────────────────────────────────────────────────
|
|
25
|
+
//
|
|
26
|
+
// It is NOT the escape. Yaver's container owns that: shake opens Yaver's own
|
|
27
|
+
// overlay with "Back to Yaver". This badge only tells you the gesture exists.
|
|
28
|
+
// Making it the exit would put the way out inside the previewed app, which is
|
|
29
|
+
// the trap the container's escape-ownership rules exist to prevent — the guest
|
|
30
|
+
// could style over it, or unmount it, and the tester would be stuck.
|
|
31
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
32
|
+
if (k2 === undefined) k2 = k;
|
|
33
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
34
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
35
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
36
|
+
}
|
|
37
|
+
Object.defineProperty(o, k2, desc);
|
|
38
|
+
}) : (function(o, m, k, k2) {
|
|
39
|
+
if (k2 === undefined) k2 = k;
|
|
40
|
+
o[k2] = m[k];
|
|
41
|
+
}));
|
|
42
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
43
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
44
|
+
}) : function(o, v) {
|
|
45
|
+
o["default"] = v;
|
|
46
|
+
});
|
|
47
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
48
|
+
var ownKeys = function(o) {
|
|
49
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
50
|
+
var ar = [];
|
|
51
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
52
|
+
return ar;
|
|
53
|
+
};
|
|
54
|
+
return ownKeys(o);
|
|
55
|
+
};
|
|
56
|
+
return function (mod) {
|
|
57
|
+
if (mod && mod.__esModule) return mod;
|
|
58
|
+
var result = {};
|
|
59
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
60
|
+
__setModuleDefault(result, mod);
|
|
61
|
+
return result;
|
|
62
|
+
};
|
|
63
|
+
})();
|
|
64
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
65
|
+
exports.hideYaverModeBadge = hideYaverModeBadge;
|
|
66
|
+
exports.showYaverModeBadge = showYaverModeBadge;
|
|
67
|
+
exports.isYaverModeBadgeHidden = isYaverModeBadgeHidden;
|
|
68
|
+
exports.YaverModeBadge = YaverModeBadge;
|
|
69
|
+
const react_1 = __importStar(require("react"));
|
|
70
|
+
const react_native_1 = require("react-native");
|
|
71
|
+
/** True only inside Yaver's container: the YaverInfo native module is
|
|
72
|
+
* registered by Yaver's app and by nothing else. Same probe ShakeDetector
|
|
73
|
+
* and P2PClient use — one answer, not three. */
|
|
74
|
+
function isInsideYaver() {
|
|
75
|
+
try {
|
|
76
|
+
return !!react_native_1.NativeModules?.YaverInfo;
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Per-RUN dismissal, shared by every mounted badge.
|
|
84
|
+
*
|
|
85
|
+
* Deliberately in memory, not storage. A permanently hidden badge recreates
|
|
86
|
+
* exactly the problem the badge exists to prevent: a tester who cannot tell an
|
|
87
|
+
* unbuilt branch from the installed app, and cannot find the way back. Polite
|
|
88
|
+
* means not nagging within a session — it does not mean permanent amnesia
|
|
89
|
+
* about which build you are looking at. A relaunch is a new context.
|
|
90
|
+
*
|
|
91
|
+
* An APP that wants it gone for good passes `modeBadge: false` at init. That is
|
|
92
|
+
* a developer making an informed choice, which is a different thing from a
|
|
93
|
+
* tester clearing their screen for a minute.
|
|
94
|
+
*/
|
|
95
|
+
let hiddenThisRun = false;
|
|
96
|
+
const hideListeners = new Set();
|
|
97
|
+
/** Hide the mark for the rest of this run. Exposed on YaverFeedback so a host
|
|
98
|
+
* can wire its own "hide" control, and used by the sheet's own button. */
|
|
99
|
+
function hideYaverModeBadge() {
|
|
100
|
+
hiddenThisRun = true;
|
|
101
|
+
hideListeners.forEach((l) => {
|
|
102
|
+
try {
|
|
103
|
+
l();
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
/* one bad listener mustn't block the others */
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
/** Bring it back — e.g. when a NEW guest bundle loads and the context changed. */
|
|
111
|
+
function showYaverModeBadge() {
|
|
112
|
+
hiddenThisRun = false;
|
|
113
|
+
hideListeners.forEach((l) => {
|
|
114
|
+
try {
|
|
115
|
+
l();
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
/* noop */
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
function isYaverModeBadgeHidden() {
|
|
123
|
+
return hiddenThisRun;
|
|
124
|
+
}
|
|
125
|
+
function YaverModeBadge({ position = 'bottom-left', force = false, dogfood = false, dogfoodLabel = 'Dogfood', onExitDogfood, }) {
|
|
126
|
+
const [open, setOpen] = (0, react_1.useState)(false);
|
|
127
|
+
const [, bump] = (0, react_1.useState)(0);
|
|
128
|
+
(0, react_1.useEffect)(() => {
|
|
129
|
+
const listener = () => bump((n) => n + 1);
|
|
130
|
+
hideListeners.add(listener);
|
|
131
|
+
return () => {
|
|
132
|
+
hideListeners.delete(listener);
|
|
133
|
+
};
|
|
134
|
+
}, []);
|
|
135
|
+
// Standalone builds render nothing at all — zero cost, zero pixels.
|
|
136
|
+
if (!force && !dogfood && !isInsideYaver())
|
|
137
|
+
return null;
|
|
138
|
+
if (hiddenThisRun)
|
|
139
|
+
return null;
|
|
140
|
+
const vertical = position.startsWith('top') ? { top: 44 } : { bottom: 28 };
|
|
141
|
+
const horizontal = position.endsWith('left') ? { left: 12 } : { right: 12 };
|
|
142
|
+
return (<>
|
|
143
|
+
<react_native_1.View
|
|
144
|
+
// The wrapper never intercepts touches; only the 22pt mark does. A
|
|
145
|
+
// full-screen overlay that swallowed taps would break the app it is
|
|
146
|
+
// supposed to be politely annotating.
|
|
147
|
+
pointerEvents="box-none" style={{ position: 'absolute', ...vertical, ...horizontal, zIndex: 9998 }}>
|
|
148
|
+
<react_native_1.Pressable onPress={() => setOpen(true)} accessibilityRole="button" accessibilityLabel={dogfood ? `Exit ${dogfoodLabel} Dogfood mode` : 'Running inside Yaver'} hitSlop={10} style={({ pressed }) => ({
|
|
149
|
+
width: 22,
|
|
150
|
+
height: 22,
|
|
151
|
+
borderRadius: 11,
|
|
152
|
+
alignItems: 'center',
|
|
153
|
+
justifyContent: 'center',
|
|
154
|
+
borderWidth: 1,
|
|
155
|
+
borderColor: 'rgba(124,92,255,0.45)',
|
|
156
|
+
backgroundColor: 'rgba(124,92,255,0.14)',
|
|
157
|
+
opacity: pressed ? 0.6 : 0.9,
|
|
158
|
+
})}>
|
|
159
|
+
<react_native_1.Text style={{ color: '#7C5CFF', fontSize: 12, fontWeight: '700', lineHeight: 14 }}>Y</react_native_1.Text>
|
|
160
|
+
</react_native_1.Pressable>
|
|
161
|
+
</react_native_1.View>
|
|
162
|
+
|
|
163
|
+
<react_native_1.Modal visible={open} transparent animationType="fade" onRequestClose={() => setOpen(false)}>
|
|
164
|
+
<react_native_1.Pressable style={{ flex: 1, backgroundColor: '#0008' }} onPress={() => setOpen(false)}>
|
|
165
|
+
<react_native_1.Pressable onPress={(e) => e.stopPropagation()} style={{
|
|
166
|
+
margin: 24,
|
|
167
|
+
marginTop: 'auto',
|
|
168
|
+
marginBottom: 48,
|
|
169
|
+
borderRadius: 16,
|
|
170
|
+
padding: 18,
|
|
171
|
+
backgroundColor: '#151519',
|
|
172
|
+
borderWidth: 1,
|
|
173
|
+
borderColor: '#2a2a32',
|
|
174
|
+
gap: 10,
|
|
175
|
+
}}>
|
|
176
|
+
<react_native_1.View style={{ flexDirection: 'row', alignItems: 'center', gap: 8 }}>
|
|
177
|
+
<react_native_1.Text style={{ color: '#7C5CFF', fontSize: 15, fontWeight: '800' }}>Y</react_native_1.Text>
|
|
178
|
+
<react_native_1.Text style={{ color: '#fff', fontSize: 15, fontWeight: '700' }}>
|
|
179
|
+
{dogfood ? `${dogfoodLabel} Dogfood mode` : 'Running inside Yaver'}
|
|
180
|
+
</react_native_1.Text>
|
|
181
|
+
</react_native_1.View>
|
|
182
|
+
<react_native_1.Text style={{ color: '#b6b6c0', fontSize: 13, lineHeight: 19 }}>
|
|
183
|
+
{dogfood
|
|
184
|
+
? 'This approved account is improving the app directly through Yaver. Tasks and re-render actions target this app instead of creating a feedback report.'
|
|
185
|
+
: 'This is a development build loaded into Yaver — not the version installed on this device. Anything unfinished here is work in progress, not a released bug.'}
|
|
186
|
+
</react_native_1.Text>
|
|
187
|
+
{dogfood ? (<react_native_1.Pressable onPress={() => react_native_1.Alert.alert('Exit Dogfood mode?', 'Return this SDK to normal Feedback mode. Your coding tasks and source changes are untouched.', [
|
|
188
|
+
{ text: 'Keep Dogfooding', style: 'cancel' },
|
|
189
|
+
{ text: 'Exit Dogfood', style: 'destructive', onPress: () => {
|
|
190
|
+
void onExitDogfood?.();
|
|
191
|
+
setOpen(false);
|
|
192
|
+
} },
|
|
193
|
+
])} style={{ paddingVertical: 10, alignItems: 'center' }}>
|
|
194
|
+
<react_native_1.Text style={{ color: '#fca5a5', fontSize: 13, fontWeight: '700' }}>Exit Dogfood mode</react_native_1.Text>
|
|
195
|
+
</react_native_1.Pressable>) : (<react_native_1.Text style={{ color: '#b6b6c0', fontSize: 13, lineHeight: 19 }}>
|
|
196
|
+
Shake the device to open Yaver's overlay, where "Back to Yaver" returns you to the installed app.
|
|
197
|
+
</react_native_1.Text>)}
|
|
198
|
+
{/* Polite means closeable. "for now", never "don't show again":
|
|
199
|
+
the badge returns next launch so nobody forgets which build
|
|
200
|
+
they're testing. */}
|
|
201
|
+
<react_native_1.Pressable onPress={() => {
|
|
202
|
+
hideYaverModeBadge();
|
|
203
|
+
setOpen(false);
|
|
204
|
+
}} style={{ paddingVertical: 10, alignItems: 'center' }}>
|
|
205
|
+
<react_native_1.Text style={{ color: '#8a8a96', fontSize: 13 }}>Hide for now</react_native_1.Text>
|
|
206
|
+
</react_native_1.Pressable>
|
|
207
|
+
<react_native_1.Text style={{ color: '#6b6b76', fontSize: 11, textAlign: 'center', lineHeight: 15 }}>
|
|
208
|
+
Hidden until you next launch this build.
|
|
209
|
+
</react_native_1.Text>
|
|
210
|
+
|
|
211
|
+
<react_native_1.Pressable onPress={() => setOpen(false)} style={{ paddingVertical: 10, alignItems: 'center' }}>
|
|
212
|
+
<react_native_1.Text style={{ color: '#8a8a96', fontSize: 13 }}>Close</react_native_1.Text>
|
|
213
|
+
</react_native_1.Pressable>
|
|
214
|
+
</react_native_1.Pressable>
|
|
215
|
+
</react_native_1.Pressable>
|
|
216
|
+
</react_native_1.Modal>
|
|
217
|
+
</>);
|
|
218
|
+
}
|
|
219
|
+
exports.default = YaverModeBadge;
|
|
@@ -8,7 +8,7 @@ describe('auth device listing', () => {
|
|
|
8
8
|
jest.clearAllMocks();
|
|
9
9
|
mockFetch.mockReset();
|
|
10
10
|
});
|
|
11
|
-
it('
|
|
11
|
+
it('returns the owner devices emitted by /devices/list', async () => {
|
|
12
12
|
mockFetch.mockResolvedValue({
|
|
13
13
|
ok: true,
|
|
14
14
|
json: () => Promise.resolve({
|
|
@@ -18,24 +18,10 @@ describe('auth device listing', () => {
|
|
|
18
18
|
name: 'My Mac',
|
|
19
19
|
platform: 'macos',
|
|
20
20
|
isOnline: true,
|
|
21
|
-
isGuest: false,
|
|
22
21
|
quicHost: '10.0.0.10',
|
|
23
22
|
quicPort: 18080,
|
|
24
23
|
lastHeartbeat: 123,
|
|
25
24
|
},
|
|
26
|
-
{
|
|
27
|
-
deviceId: 'guest-1',
|
|
28
|
-
name: 'yaver-test-ephemeral',
|
|
29
|
-
platform: 'linux',
|
|
30
|
-
isOnline: true,
|
|
31
|
-
isGuest: true,
|
|
32
|
-
hostName: 'Host User',
|
|
33
|
-
hostEmail: 'host@example.com',
|
|
34
|
-
accessScope: 'shared-scoped',
|
|
35
|
-
quicHost: '198.51.100.20',
|
|
36
|
-
quicPort: 18080,
|
|
37
|
-
lastHeartbeat: 456,
|
|
38
|
-
},
|
|
39
25
|
],
|
|
40
26
|
}),
|
|
41
27
|
});
|
|
@@ -44,39 +30,6 @@ describe('auth device listing', () => {
|
|
|
44
30
|
headers: { Authorization: 'Bearer sdk-user-token' },
|
|
45
31
|
}));
|
|
46
32
|
expect(result.owned).toHaveLength(1);
|
|
47
|
-
expect(result.shared).toHaveLength(1);
|
|
48
33
|
expect(result.owned[0].deviceId).toBe('own-1');
|
|
49
|
-
expect(result.shared[0]).toMatchObject({
|
|
50
|
-
deviceId: 'guest-1',
|
|
51
|
-
isGuest: true,
|
|
52
|
-
hostEmail: 'host@example.com',
|
|
53
|
-
accessScope: 'shared-scoped',
|
|
54
|
-
});
|
|
55
|
-
});
|
|
56
|
-
it('shows shared devices even when the guest owns no machines', async () => {
|
|
57
|
-
mockFetch.mockResolvedValue({
|
|
58
|
-
ok: true,
|
|
59
|
-
json: () => Promise.resolve({
|
|
60
|
-
devices: [
|
|
61
|
-
{
|
|
62
|
-
deviceId: 'guest-only',
|
|
63
|
-
name: 'yaver-test-ephemeral',
|
|
64
|
-
platform: 'linux',
|
|
65
|
-
isOnline: true,
|
|
66
|
-
isGuest: true,
|
|
67
|
-
hostName: 'Host User',
|
|
68
|
-
hostEmail: 'host@example.com',
|
|
69
|
-
accessScope: 'shared-scoped',
|
|
70
|
-
quicHost: '198.51.100.20',
|
|
71
|
-
quicPort: 18080,
|
|
72
|
-
lastHeartbeat: 789,
|
|
73
|
-
},
|
|
74
|
-
],
|
|
75
|
-
}),
|
|
76
|
-
});
|
|
77
|
-
const result = await (0, auth_1.listReachableDevices)('guest-only-token');
|
|
78
|
-
expect(result.owned).toEqual([]);
|
|
79
|
-
expect(result.shared).toHaveLength(1);
|
|
80
|
-
expect(result.shared[0].deviceId).toBe('guest-only');
|
|
81
34
|
});
|
|
82
35
|
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// BlackBox relay-password sourcing.
|
|
3
|
+
//
|
|
4
|
+
// This exists because BlackBox.start() used to read the relay password off
|
|
5
|
+
// the feedback config:
|
|
6
|
+
//
|
|
7
|
+
// BlackBox.relayPassword =
|
|
8
|
+
// (feedbackConfig as { relayPassword?: string }).relayPassword ?? '';
|
|
9
|
+
//
|
|
10
|
+
// `relayPassword` is not a key on FeedbackConfig. The cast is what stopped
|
|
11
|
+
// the compiler from saying so, and the field was therefore permanently ''.
|
|
12
|
+
// Since every X-Relay-Password header is written behind an
|
|
13
|
+
// `if (BlackBox.relayPassword)` guard, the header was never sent, and the
|
|
14
|
+
// relay 401s an empty password (relay/server.go). Net effect: on cellular
|
|
15
|
+
// (the only time the relay is used at all) the SSE command channel died,
|
|
16
|
+
// so the reload that lands after an agent fix never fired. On-LAN the
|
|
17
|
+
// password is unused, so this was invisible in local dev — it only ever
|
|
18
|
+
// broke remote users.
|
|
19
|
+
//
|
|
20
|
+
// The contract pinned here: BlackBox takes its relay password from
|
|
21
|
+
// YaverFeedback.getRelayPassword(), the same source P2PClient uses.
|
|
22
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
+
const BlackBox_1 = require("../BlackBox");
|
|
24
|
+
const YaverFeedback_1 = require("../YaverFeedback");
|
|
25
|
+
jest.mock('react-native', () => ({
|
|
26
|
+
Platform: { OS: 'ios' },
|
|
27
|
+
}));
|
|
28
|
+
jest.useFakeTimers();
|
|
29
|
+
const mockFetch = jest.fn();
|
|
30
|
+
global.fetch = mockFetch;
|
|
31
|
+
class MockAbortController {
|
|
32
|
+
constructor() {
|
|
33
|
+
this.signal = { aborted: false };
|
|
34
|
+
this.abort = jest.fn(() => {
|
|
35
|
+
this.signal.aborted = true;
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
global.AbortController = MockAbortController;
|
|
40
|
+
function emptySse() {
|
|
41
|
+
return new ReadableStream({
|
|
42
|
+
start(controller) {
|
|
43
|
+
controller.close();
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
beforeEach(() => {
|
|
48
|
+
jest.clearAllMocks();
|
|
49
|
+
mockFetch.mockImplementation((url) => {
|
|
50
|
+
if (String(url).includes('/blackbox/command-stream')) {
|
|
51
|
+
return Promise.resolve({ ok: true, body: emptySse() });
|
|
52
|
+
}
|
|
53
|
+
return Promise.resolve({ ok: true, json: () => Promise.resolve({}) });
|
|
54
|
+
});
|
|
55
|
+
// A relay-routed agent URL — the shape discovery produces off-LAN.
|
|
56
|
+
YaverFeedback_1.YaverFeedback.init({
|
|
57
|
+
agentUrl: 'https://public.yaver.io/d/macmini-1',
|
|
58
|
+
authToken: 'tok',
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
afterEach(() => {
|
|
62
|
+
BlackBox_1.BlackBox.stop();
|
|
63
|
+
jest.restoreAllMocks();
|
|
64
|
+
});
|
|
65
|
+
describe('BlackBox relay password', () => {
|
|
66
|
+
it('sends X-Relay-Password on the SSE command stream, sourced from getRelayPassword()', async () => {
|
|
67
|
+
jest.spyOn(YaverFeedback_1.YaverFeedback, 'getRelayPassword').mockReturnValue('s3cret-relay-pw');
|
|
68
|
+
BlackBox_1.BlackBox.start({ deviceId: 'dev-abc', appName: 'talos-mobile' });
|
|
69
|
+
await Promise.resolve();
|
|
70
|
+
await Promise.resolve();
|
|
71
|
+
const sseCall = mockFetch.mock.calls.find(([url]) => String(url).includes('/blackbox/command-stream'));
|
|
72
|
+
expect(sseCall).toBeDefined();
|
|
73
|
+
const [, init] = sseCall;
|
|
74
|
+
expect(init.headers).toEqual(expect.objectContaining({ 'X-Relay-Password': 's3cret-relay-pw' }));
|
|
75
|
+
});
|
|
76
|
+
it('sends X-Relay-Password on the event flush', async () => {
|
|
77
|
+
jest.spyOn(YaverFeedback_1.YaverFeedback, 'getRelayPassword').mockReturnValue('s3cret-relay-pw');
|
|
78
|
+
// maxBufferSize:1 makes push() flush synchronously on the first event,
|
|
79
|
+
// so this doesn't hang on interval semantics.
|
|
80
|
+
BlackBox_1.BlackBox.start({ deviceId: 'dev-abc', maxBufferSize: 1 });
|
|
81
|
+
BlackBox_1.BlackBox.log('hello');
|
|
82
|
+
await Promise.resolve();
|
|
83
|
+
const flush = mockFetch.mock.calls.find(([url]) => String(url).includes('/blackbox/events'));
|
|
84
|
+
expect(flush).toBeDefined();
|
|
85
|
+
const [, init] = flush;
|
|
86
|
+
expect(init.headers).toEqual(expect.objectContaining({ 'X-Relay-Password': 's3cret-relay-pw' }));
|
|
87
|
+
});
|
|
88
|
+
it('omits the header entirely when there is no relay password (direct LAN)', async () => {
|
|
89
|
+
// An empty header value is itself a 401 at the relay, so "no password"
|
|
90
|
+
// must mean "no header", not "empty header".
|
|
91
|
+
jest.spyOn(YaverFeedback_1.YaverFeedback, 'getRelayPassword').mockReturnValue('');
|
|
92
|
+
BlackBox_1.BlackBox.start({ deviceId: 'dev-abc' });
|
|
93
|
+
await Promise.resolve();
|
|
94
|
+
await Promise.resolve();
|
|
95
|
+
const sseCall = mockFetch.mock.calls.find(([url]) => String(url).includes('/blackbox/command-stream'));
|
|
96
|
+
expect(sseCall).toBeDefined();
|
|
97
|
+
const [, init] = sseCall;
|
|
98
|
+
expect(init.headers).not.toHaveProperty('X-Relay-Password');
|
|
99
|
+
});
|
|
100
|
+
it('does not read a relayPassword key off the feedback config', () => {
|
|
101
|
+
// The original bug in one assertion: FeedbackConfig has no such key, so
|
|
102
|
+
// anyone reintroducing that read gets '' and silently breaks the relay.
|
|
103
|
+
expect(YaverFeedback_1.YaverFeedback.getConfig()).not.toHaveProperty('relayPassword');
|
|
104
|
+
});
|
|
105
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// BlackBox auto-start config passthrough.
|
|
3
|
+
//
|
|
4
|
+
// The natural way to configure the flight recorder — and the one the README's
|
|
5
|
+
// own snippet shows — is:
|
|
6
|
+
//
|
|
7
|
+
// YaverFeedback.init({ trigger: 'shake' });
|
|
8
|
+
// BlackBox.start({ appName: 'my-app' });
|
|
9
|
+
//
|
|
10
|
+
// That start() early-returns: a zero-config init has no agentUrl yet, because
|
|
11
|
+
// discovery resolves it asynchronously. The SDK's autoStartBlackBox then fires
|
|
12
|
+
// ~500ms later once the agent and token exist — and used to call start() with
|
|
13
|
+
// no arguments, quietly replacing the host's config with defaults and leaving
|
|
14
|
+
// appName as ''. Hosts had no way to tell: the recorder streamed, just
|
|
15
|
+
// anonymously.
|
|
16
|
+
//
|
|
17
|
+
// config.blackBox is now the supported channel, and auto-start honours it.
|
|
18
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
+
const BlackBox_1 = require("../BlackBox");
|
|
20
|
+
const YaverFeedback_1 = require("../YaverFeedback");
|
|
21
|
+
jest.mock('react-native', () => ({
|
|
22
|
+
Platform: { OS: 'ios' },
|
|
23
|
+
DeviceEventEmitter: { emit: jest.fn(), addListener: jest.fn() },
|
|
24
|
+
NativeModules: {},
|
|
25
|
+
}));
|
|
26
|
+
jest.mock('../ShakeDetector', () => ({
|
|
27
|
+
ShakeDetector: jest.fn().mockImplementation(() => ({
|
|
28
|
+
start: jest.fn(),
|
|
29
|
+
stop: jest.fn(),
|
|
30
|
+
})),
|
|
31
|
+
}));
|
|
32
|
+
jest.useFakeTimers();
|
|
33
|
+
const mockFetch = jest.fn(() => Promise.resolve({ ok: true, json: () => Promise.resolve({}), body: null }));
|
|
34
|
+
global.fetch = mockFetch;
|
|
35
|
+
class MockAbortController {
|
|
36
|
+
constructor() {
|
|
37
|
+
this.signal = { aborted: false };
|
|
38
|
+
this.abort = jest.fn();
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
global.AbortController = MockAbortController;
|
|
42
|
+
beforeEach(() => {
|
|
43
|
+
jest.clearAllMocks();
|
|
44
|
+
YaverFeedback_1.YaverFeedback.destroy();
|
|
45
|
+
});
|
|
46
|
+
afterEach(() => {
|
|
47
|
+
BlackBox_1.BlackBox.stop();
|
|
48
|
+
YaverFeedback_1.YaverFeedback.destroy();
|
|
49
|
+
});
|
|
50
|
+
describe('autoStartBlackBox config passthrough', () => {
|
|
51
|
+
it('starts BlackBox with the config passed on init', async () => {
|
|
52
|
+
const startSpy = jest.spyOn(BlackBox_1.BlackBox, 'start').mockImplementation(() => { });
|
|
53
|
+
YaverFeedback_1.YaverFeedback.init({
|
|
54
|
+
trigger: 'shake',
|
|
55
|
+
agentUrl: 'http://localhost:18080',
|
|
56
|
+
authToken: 'tok',
|
|
57
|
+
blackBox: { appName: 'talos-mobile', flushInterval: 3000, maxBufferSize: 25 },
|
|
58
|
+
});
|
|
59
|
+
await jest.advanceTimersByTimeAsync(600);
|
|
60
|
+
expect(startSpy).toHaveBeenCalledWith(expect.objectContaining({
|
|
61
|
+
appName: 'talos-mobile',
|
|
62
|
+
flushInterval: 3000,
|
|
63
|
+
maxBufferSize: 25,
|
|
64
|
+
}));
|
|
65
|
+
startSpy.mockRestore();
|
|
66
|
+
});
|
|
67
|
+
it('still auto-starts when no blackBox config is given', async () => {
|
|
68
|
+
const startSpy = jest.spyOn(BlackBox_1.BlackBox, 'start').mockImplementation(() => { });
|
|
69
|
+
YaverFeedback_1.YaverFeedback.init({
|
|
70
|
+
trigger: 'shake',
|
|
71
|
+
agentUrl: 'http://localhost:18080',
|
|
72
|
+
authToken: 'tok',
|
|
73
|
+
});
|
|
74
|
+
await jest.advanceTimersByTimeAsync(600);
|
|
75
|
+
expect(startSpy).toHaveBeenCalled();
|
|
76
|
+
startSpy.mockRestore();
|
|
77
|
+
});
|
|
78
|
+
it('does not auto-start when autoStartBlackBox is false', async () => {
|
|
79
|
+
const startSpy = jest.spyOn(BlackBox_1.BlackBox, 'start').mockImplementation(() => { });
|
|
80
|
+
YaverFeedback_1.YaverFeedback.init({
|
|
81
|
+
trigger: 'shake',
|
|
82
|
+
agentUrl: 'http://localhost:18080',
|
|
83
|
+
authToken: 'tok',
|
|
84
|
+
autoStartBlackBox: false,
|
|
85
|
+
blackBox: { appName: 'talos-mobile' },
|
|
86
|
+
});
|
|
87
|
+
await jest.advanceTimersByTimeAsync(600);
|
|
88
|
+
expect(startSpy).not.toHaveBeenCalled();
|
|
89
|
+
startSpy.mockRestore();
|
|
90
|
+
});
|
|
91
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|