yaver-feedback-react-native 0.5.5 → 0.6.0
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 +26 -4
- package/dist/LoginScreen.d.ts +3 -4
- package/dist/LoginScreen.js +155 -224
- package/dist/auth.d.ts +40 -34
- package/dist/auth.js +113 -53
- package/dist/index.d.ts +2 -2
- package/dist/index.js +4 -3
- package/dist/types.d.ts +2 -1
- package/package.json +7 -2
- package/src/LoginScreen.tsx +250 -313
- package/src/auth.ts +145 -68
- package/src/index.ts +3 -4
- package/src/types.ts +2 -1
package/dist/auth.js
CHANGED
|
@@ -2,25 +2,22 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Authentication + device/agent discovery API used by the Yaver Feedback SDK.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
* covers what the embedded login/machine-picker flow needs:
|
|
5
|
+
* Mirrors mobile/src/lib/auth.ts:
|
|
7
6
|
*
|
|
8
|
-
* -
|
|
9
|
-
*
|
|
10
|
-
*
|
|
7
|
+
* - Native Apple Sign-In (`POST /auth/apple-native`) on iOS via
|
|
8
|
+
* `expo-apple-authentication`.
|
|
9
|
+
* - In-app browser OAuth for Google/Microsoft/GitHub/GitLab via
|
|
10
|
+
* `expo-web-browser`'s `openAuthSessionAsync` — same callback URL
|
|
11
|
+
* (`yaver://oauth-callback`) the Yaver mobile app uses.
|
|
11
12
|
* - Email / password sign-up + login (no 2FA flow — for SDK simplicity).
|
|
12
|
-
* - Token validation
|
|
13
|
+
* - Token validation.
|
|
13
14
|
* - `/devices/list` → owned + shared (guest) remote dev machines.
|
|
14
15
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* Token persistence uses `@react-native-async-storage/async-storage` (already
|
|
19
|
-
* a peer dep). SecureStore is intentionally avoided to keep the SDK portable
|
|
20
|
-
* to any RN host app.
|
|
16
|
+
* Mobile-only. A web equivalent will ship as a separate `yaver-web-feedback`
|
|
17
|
+
* package; do not import this module from a browser bundle.
|
|
21
18
|
*/
|
|
22
19
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
-
exports.DEFAULT_WEB_BASE_URL = exports.DEFAULT_CONVEX_SITE_URL = void 0;
|
|
20
|
+
exports.DEFAULT_OAUTH_REDIRECT = exports.DEFAULT_WEB_BASE_URL = exports.DEFAULT_CONVEX_SITE_URL = void 0;
|
|
24
21
|
exports.configureAuthEndpoints = configureAuthEndpoints;
|
|
25
22
|
exports.getConvexSiteUrl = getConvexSiteUrl;
|
|
26
23
|
exports.getWebBaseUrl = getWebBaseUrl;
|
|
@@ -33,8 +30,8 @@ exports.getSelectedDeviceId = getSelectedDeviceId;
|
|
|
33
30
|
exports.saveSelectedDeviceId = saveSelectedDeviceId;
|
|
34
31
|
exports.clearSelectedDeviceId = clearSelectedDeviceId;
|
|
35
32
|
exports.validateToken = validateToken;
|
|
36
|
-
exports.
|
|
37
|
-
exports.
|
|
33
|
+
exports.signInWithApple = signInWithApple;
|
|
34
|
+
exports.signInWithOAuth = signInWithOAuth;
|
|
38
35
|
exports.signupWithEmail = signupWithEmail;
|
|
39
36
|
exports.loginWithEmail = loginWithEmail;
|
|
40
37
|
exports.listReachableDevices = listReachableDevices;
|
|
@@ -46,6 +43,21 @@ try {
|
|
|
46
43
|
catch {
|
|
47
44
|
// not installed — token persistence disabled, caller must pass authToken
|
|
48
45
|
}
|
|
46
|
+
let WebBrowser = null;
|
|
47
|
+
try {
|
|
48
|
+
WebBrowser = require('expo-web-browser');
|
|
49
|
+
WebBrowser?.maybeCompleteAuthSession();
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
// optional
|
|
53
|
+
}
|
|
54
|
+
let AppleAuth = null;
|
|
55
|
+
try {
|
|
56
|
+
AppleAuth = require('expo-apple-authentication');
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
// optional — Apple sign-in falls back to in-app browser OAuth
|
|
60
|
+
}
|
|
49
61
|
const TOKEN_KEY = 'yaver_feedback_auth_token';
|
|
50
62
|
const USER_KEY = 'yaver_feedback_user';
|
|
51
63
|
const DEVICE_KEY = 'yaver_feedback_selected_device';
|
|
@@ -178,54 +190,102 @@ async function validateToken(token) {
|
|
|
178
190
|
return null;
|
|
179
191
|
}
|
|
180
192
|
}
|
|
193
|
+
// ─── Native Apple Sign-In ─────────────────────────────────────────────
|
|
181
194
|
/**
|
|
182
|
-
*
|
|
183
|
-
*
|
|
184
|
-
*
|
|
195
|
+
* Sign in with Apple using the native ASAuthorization flow. Requires
|
|
196
|
+
* `expo-apple-authentication` installed and the host app's bundle to have
|
|
197
|
+
* the "Sign in with Apple" capability enabled. iOS only.
|
|
198
|
+
*
|
|
199
|
+
* Throws `cancelled` if the user dismisses the sheet.
|
|
185
200
|
*/
|
|
186
|
-
async function
|
|
187
|
-
|
|
201
|
+
async function signInWithApple() {
|
|
202
|
+
if (!AppleAuth) {
|
|
203
|
+
throw new Error('expo-apple-authentication is not installed. Add it as a peer dep to enable native Apple Sign-In.');
|
|
204
|
+
}
|
|
205
|
+
const available = await AppleAuth.isAvailableAsync();
|
|
206
|
+
if (!available) {
|
|
207
|
+
throw new Error('Apple Sign-In is not available on this device');
|
|
208
|
+
}
|
|
209
|
+
let credential;
|
|
210
|
+
try {
|
|
211
|
+
credential = await AppleAuth.signInAsync({
|
|
212
|
+
requestedScopes: [
|
|
213
|
+
AppleAuth.AppleAuthenticationScope.FULL_NAME,
|
|
214
|
+
AppleAuth.AppleAuthenticationScope.EMAIL,
|
|
215
|
+
],
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
catch (err) {
|
|
219
|
+
if (err?.code === 'ERR_REQUEST_CANCELED') {
|
|
220
|
+
throw new Error('cancelled');
|
|
221
|
+
}
|
|
222
|
+
throw err;
|
|
223
|
+
}
|
|
224
|
+
if (!credential.identityToken) {
|
|
225
|
+
throw new Error('Apple did not return an identity token');
|
|
226
|
+
}
|
|
227
|
+
const fullName = [credential.fullName?.givenName, credential.fullName?.familyName]
|
|
228
|
+
.filter(Boolean)
|
|
229
|
+
.join(' ') || undefined;
|
|
230
|
+
const res = await fetch(`${convexSiteUrl}/auth/apple-native`, {
|
|
188
231
|
method: 'POST',
|
|
189
232
|
headers: { 'Content-Type': 'application/json' },
|
|
190
|
-
body: JSON.stringify({
|
|
191
|
-
machineName: opts?.machineName,
|
|
192
|
-
platform: opts?.platform,
|
|
193
|
-
preferredProvider: opts?.preferredProvider,
|
|
194
|
-
environment: 'feedback-sdk',
|
|
195
|
-
}),
|
|
233
|
+
body: JSON.stringify({ identityToken: credential.identityToken, fullName }),
|
|
196
234
|
});
|
|
197
235
|
if (!res.ok) {
|
|
198
|
-
const
|
|
199
|
-
throw new Error(
|
|
236
|
+
const body = await res.text().catch(() => '');
|
|
237
|
+
throw new Error(body || 'Apple sign-in failed');
|
|
200
238
|
}
|
|
201
239
|
const data = await res.json();
|
|
202
|
-
|
|
203
|
-
if (opts?.preferredProvider) {
|
|
204
|
-
params.set('preferredProvider', opts.preferredProvider);
|
|
205
|
-
}
|
|
206
|
-
return {
|
|
207
|
-
userCode: data.userCode,
|
|
208
|
-
deviceCode: data.deviceCode,
|
|
209
|
-
expiresAt: data.expiresAt,
|
|
210
|
-
verificationUrl: `${webBaseUrl}/auth/device?${params.toString()}`,
|
|
211
|
-
};
|
|
240
|
+
return { token: data.token, userId: data.userId };
|
|
212
241
|
}
|
|
213
|
-
|
|
242
|
+
// ─── In-app browser OAuth (Google / GitHub / GitLab / Microsoft) ──────
|
|
243
|
+
/**
|
|
244
|
+
* Default OAuth redirect — the same callback the Yaver mobile app uses
|
|
245
|
+
* (`yaver://oauth-callback`). `WebBrowser.openAuthSessionAsync` intercepts
|
|
246
|
+
* this redirect inside the auth session, so the host app does not need to
|
|
247
|
+
* register the scheme on iOS. On Android, add an `<intent-filter>` for
|
|
248
|
+
* `yaver://oauth-callback` in the host app's AndroidManifest.xml.
|
|
249
|
+
*/
|
|
250
|
+
exports.DEFAULT_OAUTH_REDIRECT = 'yaver://oauth-callback';
|
|
251
|
+
/**
|
|
252
|
+
* Sign in through the in-app browser via yaver.io. Opens
|
|
253
|
+
* `https://yaver.io/api/auth/oauth/<provider>?client=mobile`, the user picks
|
|
254
|
+
* an OAuth provider, and the web callback redirects back to
|
|
255
|
+
* `yaver://oauth-callback?token=...` which `openAuthSessionAsync` captures
|
|
256
|
+
* inside the auth session. No deep-link wiring required on iOS.
|
|
257
|
+
*
|
|
258
|
+
* Throws `cancelled` if the user dismisses the browser.
|
|
259
|
+
*/
|
|
260
|
+
async function signInWithOAuth(provider, opts) {
|
|
261
|
+
if (!WebBrowser) {
|
|
262
|
+
throw new Error('expo-web-browser is not installed. Add it as a peer dep to enable OAuth sign-in.');
|
|
263
|
+
}
|
|
264
|
+
const redirectUrl = opts?.redirectUrl ?? exports.DEFAULT_OAUTH_REDIRECT;
|
|
265
|
+
const params = new URLSearchParams({ client: 'mobile' });
|
|
266
|
+
const authUrl = `${webBaseUrl}/api/auth/oauth/${provider}?${params.toString()}`;
|
|
267
|
+
const result = await WebBrowser.openAuthSessionAsync(authUrl, redirectUrl, {
|
|
268
|
+
preferEphemeralSession: opts?.preferEphemeralSession ?? false,
|
|
269
|
+
showInRecents: true,
|
|
270
|
+
});
|
|
271
|
+
if (result.type !== 'success' || !result.url) {
|
|
272
|
+
throw new Error('cancelled');
|
|
273
|
+
}
|
|
274
|
+
let token = null;
|
|
214
275
|
try {
|
|
215
|
-
const
|
|
216
|
-
|
|
217
|
-
return { status: 'expired' };
|
|
218
|
-
const data = await res.json();
|
|
219
|
-
if (data.status === 'authorized' && typeof data.token === 'string') {
|
|
220
|
-
return { status: 'authorized', token: data.token };
|
|
221
|
-
}
|
|
222
|
-
if (data.status === 'pending')
|
|
223
|
-
return { status: 'pending' };
|
|
224
|
-
return { status: 'expired' };
|
|
276
|
+
const parsed = new URL(result.url);
|
|
277
|
+
token = parsed.searchParams.get('token');
|
|
225
278
|
}
|
|
226
279
|
catch {
|
|
227
|
-
|
|
280
|
+
// best-effort fallback for odd schemes
|
|
281
|
+
const match = result.url.match(/[?&]token=([^&]+)/);
|
|
282
|
+
if (match)
|
|
283
|
+
token = decodeURIComponent(match[1]);
|
|
284
|
+
}
|
|
285
|
+
if (!token) {
|
|
286
|
+
throw new Error('OAuth callback did not include a token');
|
|
228
287
|
}
|
|
288
|
+
return { token };
|
|
229
289
|
}
|
|
230
290
|
// ─── Email / password (no 2FA) ────────────────────────────────────────
|
|
231
291
|
async function signupWithEmail(fullName, email, password) {
|
|
@@ -252,9 +312,9 @@ async function loginWithEmail(email, password) {
|
|
|
252
312
|
}
|
|
253
313
|
const data = await res.json();
|
|
254
314
|
if (data?.requires2fa) {
|
|
255
|
-
// SDK login surface does not handle 2FA — direct the user to
|
|
256
|
-
//
|
|
257
|
-
throw new Error('2FA is enabled on this account. Sign in
|
|
315
|
+
// SDK login surface does not handle 2FA — direct the user to sign in
|
|
316
|
+
// through one of the OAuth providers, which complete 2FA on the web.
|
|
317
|
+
throw new Error('2FA is enabled on this account. Sign in with Apple/Google/GitHub/GitLab/Microsoft instead.');
|
|
258
318
|
}
|
|
259
319
|
return { token: data.token, userId: data.userId };
|
|
260
320
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -38,8 +38,8 @@ export { ShakeDetector } from './ShakeDetector';
|
|
|
38
38
|
export { FloatingButton } from './FloatingButton';
|
|
39
39
|
export { FeedbackModal } from './FeedbackModal';
|
|
40
40
|
export { FixReport } from './FixReport';
|
|
41
|
-
export { configureAuthEndpoints, getConvexSiteUrl, getWebBaseUrl, getToken, saveToken, clearToken, getUser, saveUser, getSelectedDeviceId, saveSelectedDeviceId, clearSelectedDeviceId, validateToken,
|
|
42
|
-
export type { OAuthProvider, User,
|
|
41
|
+
export { configureAuthEndpoints, getConvexSiteUrl, getWebBaseUrl, getToken, saveToken, clearToken, getUser, saveUser, getSelectedDeviceId, saveSelectedDeviceId, clearSelectedDeviceId, validateToken, signInWithApple, signInWithOAuth, signupWithEmail, loginWithEmail, listReachableDevices, DEFAULT_CONVEX_SITE_URL, DEFAULT_WEB_BASE_URL, DEFAULT_OAUTH_REDIRECT, } from './auth';
|
|
42
|
+
export type { OAuthProvider, User, RemoteDevice, DeviceList, } from './auth';
|
|
43
43
|
export { captureScreenshot, startAudioRecording, stopAudioRecording } from './capture';
|
|
44
44
|
export { uploadFeedback } from './upload';
|
|
45
45
|
export type { FeedbackConfig, FeedbackBundle, FeedbackMetadata, DeviceInfo, AppInfo, TimelineEvent, FeedbackReport, AgentCommentary, FeedbackStreamEvent, VoiceCapability, CapturedError, TestFix, TestSession, } from './types';
|
package/dist/index.js
CHANGED
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
* ```
|
|
24
24
|
*/
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
-
exports.uploadFeedback = exports.stopAudioRecording = exports.startAudioRecording = exports.captureScreenshot = exports.DEFAULT_WEB_BASE_URL = exports.DEFAULT_CONVEX_SITE_URL = exports.listReachableDevices = exports.loginWithEmail = exports.signupWithEmail = exports.
|
|
26
|
+
exports.uploadFeedback = exports.stopAudioRecording = exports.startAudioRecording = exports.captureScreenshot = exports.DEFAULT_OAUTH_REDIRECT = exports.DEFAULT_WEB_BASE_URL = exports.DEFAULT_CONVEX_SITE_URL = exports.listReachableDevices = exports.loginWithEmail = exports.signupWithEmail = exports.signInWithOAuth = exports.signInWithApple = exports.validateToken = exports.clearSelectedDeviceId = exports.saveSelectedDeviceId = exports.getSelectedDeviceId = exports.saveUser = exports.getUser = exports.clearToken = exports.saveToken = exports.getToken = exports.getWebBaseUrl = exports.getConvexSiteUrl = exports.configureAuthEndpoints = exports.FixReport = exports.FeedbackModal = exports.FloatingButton = exports.ShakeDetector = exports.AuthOverlay = exports.YaverMachinePickerScreen = exports.YaverLoginScreen = exports.YaverConnectionScreen = exports.P2PClient = exports.YaverDiscovery = exports.initExpo = exports.YaverUpdates = exports.BlackBox = exports.YaverFeedback = void 0;
|
|
27
27
|
var YaverFeedback_1 = require("./YaverFeedback");
|
|
28
28
|
Object.defineProperty(exports, "YaverFeedback", { enumerable: true, get: function () { return YaverFeedback_1.YaverFeedback; } });
|
|
29
29
|
var BlackBox_1 = require("./BlackBox");
|
|
@@ -65,13 +65,14 @@ Object.defineProperty(exports, "getSelectedDeviceId", { enumerable: true, get: f
|
|
|
65
65
|
Object.defineProperty(exports, "saveSelectedDeviceId", { enumerable: true, get: function () { return auth_1.saveSelectedDeviceId; } });
|
|
66
66
|
Object.defineProperty(exports, "clearSelectedDeviceId", { enumerable: true, get: function () { return auth_1.clearSelectedDeviceId; } });
|
|
67
67
|
Object.defineProperty(exports, "validateToken", { enumerable: true, get: function () { return auth_1.validateToken; } });
|
|
68
|
-
Object.defineProperty(exports, "
|
|
69
|
-
Object.defineProperty(exports, "
|
|
68
|
+
Object.defineProperty(exports, "signInWithApple", { enumerable: true, get: function () { return auth_1.signInWithApple; } });
|
|
69
|
+
Object.defineProperty(exports, "signInWithOAuth", { enumerable: true, get: function () { return auth_1.signInWithOAuth; } });
|
|
70
70
|
Object.defineProperty(exports, "signupWithEmail", { enumerable: true, get: function () { return auth_1.signupWithEmail; } });
|
|
71
71
|
Object.defineProperty(exports, "loginWithEmail", { enumerable: true, get: function () { return auth_1.loginWithEmail; } });
|
|
72
72
|
Object.defineProperty(exports, "listReachableDevices", { enumerable: true, get: function () { return auth_1.listReachableDevices; } });
|
|
73
73
|
Object.defineProperty(exports, "DEFAULT_CONVEX_SITE_URL", { enumerable: true, get: function () { return auth_1.DEFAULT_CONVEX_SITE_URL; } });
|
|
74
74
|
Object.defineProperty(exports, "DEFAULT_WEB_BASE_URL", { enumerable: true, get: function () { return auth_1.DEFAULT_WEB_BASE_URL; } });
|
|
75
|
+
Object.defineProperty(exports, "DEFAULT_OAUTH_REDIRECT", { enumerable: true, get: function () { return auth_1.DEFAULT_OAUTH_REDIRECT; } });
|
|
75
76
|
var capture_1 = require("./capture");
|
|
76
77
|
Object.defineProperty(exports, "captureScreenshot", { enumerable: true, get: function () { return capture_1.captureScreenshot; } });
|
|
77
78
|
Object.defineProperty(exports, "startAudioRecording", { enumerable: true, get: function () { return capture_1.startAudioRecording; } });
|
package/dist/types.d.ts
CHANGED
|
@@ -4,7 +4,8 @@ export interface FeedbackConfig {
|
|
|
4
4
|
/**
|
|
5
5
|
* Auth token for the Yaver agent. Optional in 0.5+: if omitted, the SDK
|
|
6
6
|
* will hydrate one from AsyncStorage or show its in-app login screen
|
|
7
|
-
* (
|
|
7
|
+
* (Apple native / OAuth in-app browser / email) the first time the user
|
|
8
|
+
* triggers feedback.
|
|
8
9
|
*/
|
|
9
10
|
authToken?: string;
|
|
10
11
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "yaver-feedback-react-native",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Visual feedback SDK for Yaver — bug reports, screen recording, voice annotations, and local-first developer workflows",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -20,7 +20,9 @@
|
|
|
20
20
|
"peerDependencies": {
|
|
21
21
|
"react": ">=18.0.0",
|
|
22
22
|
"react-native": ">=0.70.0",
|
|
23
|
-
"@react-native-async-storage/async-storage": ">=1.17.0"
|
|
23
|
+
"@react-native-async-storage/async-storage": ">=1.17.0",
|
|
24
|
+
"expo-web-browser": ">=12.0.0",
|
|
25
|
+
"expo-apple-authentication": ">=6.0.0"
|
|
24
26
|
},
|
|
25
27
|
"peerDependenciesMeta": {
|
|
26
28
|
"@expo/config-plugins": {
|
|
@@ -28,6 +30,9 @@
|
|
|
28
30
|
},
|
|
29
31
|
"expo-constants": {
|
|
30
32
|
"optional": true
|
|
33
|
+
},
|
|
34
|
+
"expo-apple-authentication": {
|
|
35
|
+
"optional": true
|
|
31
36
|
}
|
|
32
37
|
},
|
|
33
38
|
"devDependencies": {
|