yaver-feedback-react-native 0.8.9 → 0.8.10

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.
@@ -1049,7 +1049,15 @@ const RunnerAuthNativeModal = ({ runner, onClose }) => {
1049
1049
  const [session, setSession] = (0, react_1.useState)(null);
1050
1050
  const [startError, setStartError] = (0, react_1.useState)(null);
1051
1051
  const [copied, setCopied] = (0, react_1.useState)(false);
1052
+ const [pasteCode, setPasteCode] = (0, react_1.useState)('');
1053
+ const [submitting, setSubmitting] = (0, react_1.useState)(false);
1054
+ const [submitError, setSubmitError] = (0, react_1.useState)(null);
1052
1055
  const startedRef = (0, react_1.useRef)(false);
1056
+ // Claude is the only runner that needs the user to paste a verifier
1057
+ // code back from platform.claude.com's callback page; Codex device-
1058
+ // auth and OpenCode (no OAuth at all) bypass this. Mirrors the
1059
+ // requiresPasteBack check in iOS YaverRunnerAuthFlowPane.swift.
1060
+ const needsPasteBack = runner === 'claude' || runner === 'claude-code';
1053
1061
  (0, react_1.useEffect)(() => {
1054
1062
  if (startedRef.current)
1055
1063
  return;
@@ -1164,9 +1172,68 @@ const RunnerAuthNativeModal = ({ runner, onClose }) => {
1164
1172
  </react_native_1.Text>
1165
1173
  </react_native_1.Pressable>
1166
1174
  </react_native_1.View>) : null}
1175
+ {needsPasteBack ? (<react_native_1.View style={{ marginTop: 14 }}>
1176
+ <react_native_1.Text style={runnerAuthModalStyles.codeLabel}>
1177
+ PASTE CODE FROM CLAUDE.COM
1178
+ </react_native_1.Text>
1179
+ <react_native_1.View style={{ flexDirection: 'row', gap: 8, marginTop: 6 }}>
1180
+ <react_native_1.View style={{
1181
+ flex: 1,
1182
+ backgroundColor: 'rgba(148,163,184,0.10)',
1183
+ borderRadius: 10,
1184
+ paddingHorizontal: 10,
1185
+ }}>
1186
+ {/* Lazy-import TextInput so the SDK doesn't pull
1187
+ extra surface from react-native at module load. */}
1188
+ {(() => {
1189
+ const { TextInput } = require('react-native');
1190
+ return (<TextInput value={pasteCode} onChangeText={(t) => {
1191
+ setPasteCode(t);
1192
+ setSubmitError(null);
1193
+ }} placeholder="paste code here" placeholderTextColor="#64748b" autoCapitalize="none" autoCorrect={false} spellCheck={false} style={{ color: '#f1f5f9', fontSize: 14, paddingVertical: 10 }}/>);
1194
+ })()}
1195
+ </react_native_1.View>
1196
+ <react_native_1.Pressable disabled={!pasteCode.trim() || submitting} onPress={async () => {
1197
+ if (!session || !pasteCode.trim())
1198
+ return;
1199
+ setSubmitting(true);
1200
+ setSubmitError(null);
1201
+ try {
1202
+ const next = await YaverFeedback_1.YaverFeedback.submitRunnerBrowserAuthCode(session.id, pasteCode.trim());
1203
+ setSession(next);
1204
+ setPasteCode('');
1205
+ }
1206
+ catch (err) {
1207
+ setSubmitError(err instanceof Error ? err.message : String(err));
1208
+ }
1209
+ finally {
1210
+ setSubmitting(false);
1211
+ }
1212
+ }} style={{
1213
+ paddingHorizontal: 14,
1214
+ justifyContent: 'center',
1215
+ backgroundColor: !pasteCode.trim() || submitting
1216
+ ? 'rgba(124,58,237,0.4)'
1217
+ : '#7c3aed',
1218
+ borderRadius: 10,
1219
+ }}>
1220
+ <react_native_1.Text style={{ color: 'white', fontWeight: '600' }}>
1221
+ {submitting ? '…' : 'Submit'}
1222
+ </react_native_1.Text>
1223
+ </react_native_1.Pressable>
1224
+ </react_native_1.View>
1225
+ {submitError ? (<react_native_1.Text style={{
1226
+ marginTop: 6,
1227
+ color: '#fca5a5',
1228
+ fontSize: 12,
1229
+ }}>
1230
+ {submitError}
1231
+ </react_native_1.Text>) : null}
1232
+ </react_native_1.View>) : null}
1167
1233
  <react_native_1.Text style={runnerAuthModalStyles.phishingHint}>
1168
- Device codes are a common phishing target. Never share this code. This dialog
1169
- turns green automatically once sign-in completes.
1234
+ {needsPasteBack
1235
+ ? 'After authorising on platform.claude.com, copy the code from the callback page and paste it above. Never share this code.'
1236
+ : 'Device codes are a common phishing target. Never share this code. This dialog turns green automatically once sign-in completes.'}
1170
1237
  </react_native_1.Text>
1171
1238
  </react_native_1.View>)}
1172
1239
  </react_native_1.View>
@@ -47,6 +47,12 @@ export declare class P2PClient {
47
47
  startRunnerBrowserAuth(runner: string): Promise<RunnerBrowserAuthSession>;
48
48
  getRunnerBrowserAuthStatus(sessionId: string): Promise<RunnerBrowserAuthSession>;
49
49
  cancelRunnerBrowserAuth(sessionId: string): Promise<void>;
50
+ /** Submit the verifier code Anthropic shows on the callback page so
51
+ * the agent can finalise claude CLI's OAuth handshake. Codex doesn't
52
+ * use this — its device-auth flow auto-resolves via polling — but
53
+ * the SDK still exposes it for symmetry with mobile/src/components/
54
+ * RunnerAuthModal.tsx and the Swift YaverRunnerAuthFlowPane. */
55
+ submitRunnerBrowserAuthCode(sessionId: string, code: string): Promise<RunnerBrowserAuthSession>;
50
56
  capabilitySnapshot(): Promise<CapabilitySnapshot | null>;
51
57
  incidents(opts?: {
52
58
  category?: string;
package/dist/P2PClient.js CHANGED
@@ -155,6 +155,25 @@ class P2PClient {
155
155
  }
156
156
  catch { /* best-effort */ }
157
157
  }
158
+ /** Submit the verifier code Anthropic shows on the callback page so
159
+ * the agent can finalise claude CLI's OAuth handshake. Codex doesn't
160
+ * use this — its device-auth flow auto-resolves via polling — but
161
+ * the SDK still exposes it for symmetry with mobile/src/components/
162
+ * RunnerAuthModal.tsx and the Swift YaverRunnerAuthFlowPane. */
163
+ async submitRunnerBrowserAuthCode(sessionId, code) {
164
+ const url = `${this.baseUrl}/runner-auth/browser/submit-code`;
165
+ const resp = await fetch(url, {
166
+ method: 'POST',
167
+ headers: { ...this.authHeaders(), 'Content-Type': 'application/json' },
168
+ body: JSON.stringify({ id: sessionId, code }),
169
+ });
170
+ if (!resp.ok) {
171
+ const text = await resp.text().catch(() => '');
172
+ throw new Error(`submitRunnerBrowserAuthCode HTTP ${resp.status}: ${text}`);
173
+ }
174
+ const data = await resp.json();
175
+ return data.session;
176
+ }
158
177
  async capabilitySnapshot() {
159
178
  try {
160
179
  const resp = await fetch(`${this.baseUrl}/capabilities/snapshot`, { headers: this.authHeaders() });
@@ -78,6 +78,10 @@ export declare class YaverFeedback {
78
78
  static startRunnerBrowserAuth(runner: string): Promise<import('./types').RunnerBrowserAuthSession>;
79
79
  static getRunnerBrowserAuthStatus(sessionId: string): Promise<import('./types').RunnerBrowserAuthSession>;
80
80
  static cancelRunnerBrowserAuth(sessionId: string): Promise<void>;
81
+ /** Submit the Claude paste-back verifier so the agent can finalise the
82
+ * OAuth handshake. RunnerAuthModal calls this after the user copies
83
+ * the code from platform.claude.com's callback page. */
84
+ static submitRunnerBrowserAuthCode(sessionId: string, code: string): Promise<import('./types').RunnerBrowserAuthSession>;
81
85
  /**
82
86
  * Sign out: clear cached token + device, tear down the P2P client. The
83
87
  * SDK stays enabled; the next feedback trigger will re-prompt for login.
@@ -571,6 +571,15 @@ class YaverFeedback {
571
571
  return;
572
572
  await p2pClient.cancelRunnerBrowserAuth(sessionId);
573
573
  }
574
+ /** Submit the Claude paste-back verifier so the agent can finalise the
575
+ * OAuth handshake. RunnerAuthModal calls this after the user copies
576
+ * the code from platform.claude.com's callback page. */
577
+ static async submitRunnerBrowserAuthCode(sessionId, code) {
578
+ if (!p2pClient) {
579
+ throw new Error('Not connected to any agent.');
580
+ }
581
+ return p2pClient.submitRunnerBrowserAuthCode(sessionId, code);
582
+ }
574
583
  /**
575
584
  * Sign out: clear cached token + device, tear down the P2P client. The
576
585
  * SDK stays enabled; the next feedback trigger will re-prompt for login.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yaver-feedback-react-native",
3
- "version": "0.8.9",
3
+ "version": "0.8.10",
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",
@@ -1251,7 +1251,15 @@ const RunnerAuthNativeModal: React.FC<{
1251
1251
  const [session, setSession] = useState<import('./types').RunnerBrowserAuthSession | null>(null);
1252
1252
  const [startError, setStartError] = useState<string | null>(null);
1253
1253
  const [copied, setCopied] = useState(false);
1254
+ const [pasteCode, setPasteCode] = useState('');
1255
+ const [submitting, setSubmitting] = useState(false);
1256
+ const [submitError, setSubmitError] = useState<string | null>(null);
1254
1257
  const startedRef = useRef(false);
1258
+ // Claude is the only runner that needs the user to paste a verifier
1259
+ // code back from platform.claude.com's callback page; Codex device-
1260
+ // auth and OpenCode (no OAuth at all) bypass this. Mirrors the
1261
+ // requiresPasteBack check in iOS YaverRunnerAuthFlowPane.swift.
1262
+ const needsPasteBack = runner === 'claude' || runner === 'claude-code';
1255
1263
 
1256
1264
  useEffect(() => {
1257
1265
  if (startedRef.current) return;
@@ -1380,9 +1388,92 @@ const RunnerAuthNativeModal: React.FC<{
1380
1388
  </Pressable>
1381
1389
  </View>
1382
1390
  ) : null}
1391
+ {needsPasteBack ? (
1392
+ <View style={{ marginTop: 14 }}>
1393
+ <Text style={runnerAuthModalStyles.codeLabel}>
1394
+ PASTE CODE FROM CLAUDE.COM
1395
+ </Text>
1396
+ <View style={{ flexDirection: 'row', gap: 8, marginTop: 6 }}>
1397
+ <View
1398
+ style={{
1399
+ flex: 1,
1400
+ backgroundColor: 'rgba(148,163,184,0.10)',
1401
+ borderRadius: 10,
1402
+ paddingHorizontal: 10,
1403
+ }}
1404
+ >
1405
+ {/* Lazy-import TextInput so the SDK doesn't pull
1406
+ extra surface from react-native at module load. */}
1407
+ {(() => {
1408
+ const { TextInput } = require('react-native');
1409
+ return (
1410
+ <TextInput
1411
+ value={pasteCode}
1412
+ onChangeText={(t: string) => {
1413
+ setPasteCode(t);
1414
+ setSubmitError(null);
1415
+ }}
1416
+ placeholder="paste code here"
1417
+ placeholderTextColor="#64748b"
1418
+ autoCapitalize="none"
1419
+ autoCorrect={false}
1420
+ spellCheck={false}
1421
+ style={{ color: '#f1f5f9', fontSize: 14, paddingVertical: 10 }}
1422
+ />
1423
+ );
1424
+ })()}
1425
+ </View>
1426
+ <Pressable
1427
+ disabled={!pasteCode.trim() || submitting}
1428
+ onPress={async () => {
1429
+ if (!session || !pasteCode.trim()) return;
1430
+ setSubmitting(true);
1431
+ setSubmitError(null);
1432
+ try {
1433
+ const next = await YaverFeedback.submitRunnerBrowserAuthCode(
1434
+ session.id,
1435
+ pasteCode.trim(),
1436
+ );
1437
+ setSession(next);
1438
+ setPasteCode('');
1439
+ } catch (err) {
1440
+ setSubmitError(err instanceof Error ? err.message : String(err));
1441
+ } finally {
1442
+ setSubmitting(false);
1443
+ }
1444
+ }}
1445
+ style={{
1446
+ paddingHorizontal: 14,
1447
+ justifyContent: 'center',
1448
+ backgroundColor:
1449
+ !pasteCode.trim() || submitting
1450
+ ? 'rgba(124,58,237,0.4)'
1451
+ : '#7c3aed',
1452
+ borderRadius: 10,
1453
+ }}
1454
+ >
1455
+ <Text style={{ color: 'white', fontWeight: '600' }}>
1456
+ {submitting ? '…' : 'Submit'}
1457
+ </Text>
1458
+ </Pressable>
1459
+ </View>
1460
+ {submitError ? (
1461
+ <Text
1462
+ style={{
1463
+ marginTop: 6,
1464
+ color: '#fca5a5',
1465
+ fontSize: 12,
1466
+ }}
1467
+ >
1468
+ {submitError}
1469
+ </Text>
1470
+ ) : null}
1471
+ </View>
1472
+ ) : null}
1383
1473
  <Text style={runnerAuthModalStyles.phishingHint}>
1384
- Device codes are a common phishing target. Never share this code. This dialog
1385
- turns green automatically once sign-in completes.
1474
+ {needsPasteBack
1475
+ ? 'After authorising on platform.claude.com, copy the code from the callback page and paste it above. Never share this code.'
1476
+ : 'Device codes are a common phishing target. Never share this code. This dialog turns green automatically once sign-in completes.'}
1386
1477
  </Text>
1387
1478
  </View>
1388
1479
  )}
package/src/P2PClient.ts CHANGED
@@ -199,6 +199,29 @@ export class P2PClient {
199
199
  try { await fetch(url, { method: 'POST', headers: this.authHeaders() }); } catch { /* best-effort */ }
200
200
  }
201
201
 
202
+ /** Submit the verifier code Anthropic shows on the callback page so
203
+ * the agent can finalise claude CLI's OAuth handshake. Codex doesn't
204
+ * use this — its device-auth flow auto-resolves via polling — but
205
+ * the SDK still exposes it for symmetry with mobile/src/components/
206
+ * RunnerAuthModal.tsx and the Swift YaverRunnerAuthFlowPane. */
207
+ async submitRunnerBrowserAuthCode(
208
+ sessionId: string,
209
+ code: string,
210
+ ): Promise<RunnerBrowserAuthSession> {
211
+ const url = `${this.baseUrl}/runner-auth/browser/submit-code`;
212
+ const resp = await fetch(url, {
213
+ method: 'POST',
214
+ headers: { ...this.authHeaders(), 'Content-Type': 'application/json' },
215
+ body: JSON.stringify({ id: sessionId, code }),
216
+ });
217
+ if (!resp.ok) {
218
+ const text = await resp.text().catch(() => '');
219
+ throw new Error(`submitRunnerBrowserAuthCode HTTP ${resp.status}: ${text}`);
220
+ }
221
+ const data = await resp.json();
222
+ return data.session as RunnerBrowserAuthSession;
223
+ }
224
+
202
225
  async capabilitySnapshot(): Promise<CapabilitySnapshot | null> {
203
226
  try {
204
227
  const resp = await fetch(`${this.baseUrl}/capabilities/snapshot`, { headers: this.authHeaders() });
@@ -596,6 +596,19 @@ export class YaverFeedback {
596
596
  await p2pClient.cancelRunnerBrowserAuth(sessionId);
597
597
  }
598
598
 
599
+ /** Submit the Claude paste-back verifier so the agent can finalise the
600
+ * OAuth handshake. RunnerAuthModal calls this after the user copies
601
+ * the code from platform.claude.com's callback page. */
602
+ static async submitRunnerBrowserAuthCode(
603
+ sessionId: string,
604
+ code: string,
605
+ ): Promise<import('./types').RunnerBrowserAuthSession> {
606
+ if (!p2pClient) {
607
+ throw new Error('Not connected to any agent.');
608
+ }
609
+ return p2pClient.submitRunnerBrowserAuthCode(sessionId, code);
610
+ }
611
+
599
612
  /**
600
613
  * Sign out: clear cached token + device, tear down the P2P client. The
601
614
  * SDK stays enabled; the next feedback trigger will re-prompt for login.