osborn 0.8.10 → 0.8.11
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/dist/claude-auth.d.ts +6 -0
- package/dist/claude-auth.js +66 -9
- package/package.json +1 -1
package/dist/claude-auth.d.ts
CHANGED
|
@@ -53,6 +53,12 @@ export declare function runClaudeAuthFlow(callbacks: ClaudeAuthCallbacks): {
|
|
|
53
53
|
* 2. ~/.claude/.credentials.json file
|
|
54
54
|
* 3. `claude auth status --json`
|
|
55
55
|
* 4. Interactive OAuth flow (setup-token)
|
|
56
|
+
*
|
|
57
|
+
* Concurrency: if a previous call is still running its OAuth flow, new
|
|
58
|
+
* callers attach to the existing flow rather than spawning a second pty.
|
|
59
|
+
* This prevents the situation where LiveKit reconnects (e.g. after a
|
|
60
|
+
* microphone-permission error) retrigger ensureClaudeAuth and the user
|
|
61
|
+
* sees two different URLs / two different code_challenges racing.
|
|
56
62
|
*/
|
|
57
63
|
export declare function ensureClaudeAuth(sendToFrontend: (type: string, payload: unknown) => void): Promise<{
|
|
58
64
|
submitCode?: (code: string) => void;
|
package/dist/claude-auth.js
CHANGED
|
@@ -354,9 +354,7 @@ export function runClaudeAuthFlow(callbacks) {
|
|
|
354
354
|
});
|
|
355
355
|
return { handle, done };
|
|
356
356
|
}
|
|
357
|
-
|
|
358
|
-
// Startup Gate
|
|
359
|
-
// ─────────────────────────────────────────
|
|
357
|
+
let inFlightAuth = null;
|
|
360
358
|
/**
|
|
361
359
|
* Ensure Claude is authenticated before proceeding.
|
|
362
360
|
*
|
|
@@ -365,8 +363,33 @@ export function runClaudeAuthFlow(callbacks) {
|
|
|
365
363
|
* 2. ~/.claude/.credentials.json file
|
|
366
364
|
* 3. `claude auth status --json`
|
|
367
365
|
* 4. Interactive OAuth flow (setup-token)
|
|
366
|
+
*
|
|
367
|
+
* Concurrency: if a previous call is still running its OAuth flow, new
|
|
368
|
+
* callers attach to the existing flow rather than spawning a second pty.
|
|
369
|
+
* This prevents the situation where LiveKit reconnects (e.g. after a
|
|
370
|
+
* microphone-permission error) retrigger ensureClaudeAuth and the user
|
|
371
|
+
* sees two different URLs / two different code_challenges racing.
|
|
368
372
|
*/
|
|
369
373
|
export async function ensureClaudeAuth(sendToFrontend) {
|
|
374
|
+
// If an auth flow is already running, attach to it and replay any
|
|
375
|
+
// state we've already captured (the URL, any waiting_code prompt).
|
|
376
|
+
if (inFlightAuth) {
|
|
377
|
+
console.log('🔑 ensureClaudeAuth called while a flow is in-flight — attaching new subscriber');
|
|
378
|
+
inFlightAuth.subscribers.push(sendToFrontend);
|
|
379
|
+
// Replay the state the frontend needs to render the modal correctly.
|
|
380
|
+
sendToFrontend('claude_auth_required', {
|
|
381
|
+
message: 'Claude authentication required. A login URL will appear shortly.',
|
|
382
|
+
});
|
|
383
|
+
if (inFlightAuth.lastUrl) {
|
|
384
|
+
sendToFrontend('claude_auth_url', { url: inFlightAuth.lastUrl });
|
|
385
|
+
}
|
|
386
|
+
if (inFlightAuth.lastStatus === 'waiting_code') {
|
|
387
|
+
sendToFrontend('claude_auth_waiting_code', {
|
|
388
|
+
message: 'Paste the authentication code from the browser.',
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
return { submitCode: inFlightAuth.submitCode, done: inFlightAuth.done };
|
|
392
|
+
}
|
|
370
393
|
// Check 0: Restore token from volume if previously persisted
|
|
371
394
|
if (!hasOAuthTokenEnv()) {
|
|
372
395
|
try {
|
|
@@ -399,28 +422,62 @@ export async function ensureClaudeAuth(sendToFrontend) {
|
|
|
399
422
|
}
|
|
400
423
|
// Check 4: Need interactive OAuth flow
|
|
401
424
|
console.log('🔑 Claude not authenticated — starting OAuth flow');
|
|
402
|
-
|
|
425
|
+
// Create the in-flight record BEFORE spawning, and fan-out every
|
|
426
|
+
// callback to all current subscribers. New subscribers that attach
|
|
427
|
+
// later get replay of lastUrl / lastStatus from the deduped path
|
|
428
|
+
// at the top of this function.
|
|
429
|
+
const subscribers = [sendToFrontend];
|
|
430
|
+
const fanout = (type, payload) => {
|
|
431
|
+
for (const sub of subscribers) {
|
|
432
|
+
try {
|
|
433
|
+
sub(type, payload);
|
|
434
|
+
}
|
|
435
|
+
catch (err) {
|
|
436
|
+
console.warn('🔑 subscriber failed:', err);
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
};
|
|
440
|
+
fanout('claude_auth_required', {
|
|
403
441
|
message: 'Claude authentication required. A login URL will appear shortly.',
|
|
404
442
|
});
|
|
405
443
|
const { handle, done } = runClaudeAuthFlow({
|
|
406
444
|
onUrl: (url) => {
|
|
407
|
-
console.log(
|
|
408
|
-
|
|
445
|
+
console.log(`📤 Sending Claude auth URL to frontend (${url.length} chars)`);
|
|
446
|
+
if (inFlightAuth) {
|
|
447
|
+
inFlightAuth.lastUrl = url;
|
|
448
|
+
inFlightAuth.lastStatus = 'waiting';
|
|
449
|
+
}
|
|
450
|
+
fanout('claude_auth_url', { url });
|
|
409
451
|
},
|
|
410
452
|
onWaitingForCode: () => {
|
|
411
453
|
console.log('📤 Sending code prompt to frontend');
|
|
412
|
-
|
|
454
|
+
if (inFlightAuth)
|
|
455
|
+
inFlightAuth.lastStatus = 'waiting_code';
|
|
456
|
+
fanout('claude_auth_waiting_code', {
|
|
413
457
|
message: 'Paste the authentication code from the browser.',
|
|
414
458
|
});
|
|
415
459
|
},
|
|
416
460
|
onComplete: () => {
|
|
417
|
-
|
|
461
|
+
fanout('claude_auth_complete', {
|
|
418
462
|
message: 'Claude authenticated successfully. Starting voice session...',
|
|
419
463
|
});
|
|
420
464
|
},
|
|
421
465
|
onError: (message) => {
|
|
422
|
-
|
|
466
|
+
fanout('claude_auth_error', { message });
|
|
423
467
|
},
|
|
424
468
|
});
|
|
469
|
+
// Publish the in-flight record so concurrent callers attach to it.
|
|
470
|
+
inFlightAuth = {
|
|
471
|
+
submitCode: handle.submitCode,
|
|
472
|
+
done,
|
|
473
|
+
lastUrl: null,
|
|
474
|
+
lastStatus: null,
|
|
475
|
+
subscribers,
|
|
476
|
+
};
|
|
477
|
+
// Clear the in-flight record once the flow settles, success or failure.
|
|
478
|
+
done.finally(() => {
|
|
479
|
+
console.log('🔑 OAuth flow settled — clearing in-flight guard');
|
|
480
|
+
inFlightAuth = null;
|
|
481
|
+
});
|
|
425
482
|
return { submitCode: handle.submitCode, done };
|
|
426
483
|
}
|