• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

agentic-dev-library / thumbcode / 21933729139

12 Feb 2026 04:36AM UTC coverage: 28.401% (+0.7%) from 27.702%
21933729139

Pull #116

github

web-flow
Merge b9d1b07d1 into c6c31bd07
Pull Request #116: refactor: decompose 9 monolith files into focused modules

406 of 2268 branches covered (17.9%)

Branch coverage included in aggregate %.

365 of 845 new or added lines in 22 files covered. (43.2%)

1 existing line in 1 file now uncovered.

1120 of 3105 relevant lines covered (36.07%)

7.7 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

65.71
/packages/core/src/auth/DeviceFlowHandler.ts
1
/**
2
 * Device Flow Handler
3
 *
4
 * Handles the initial phase of GitHub Device Flow OAuth:
5
 * requesting a device code and preparing for user authorization.
6
 */
7

8
import { GITHUB_OAUTH } from '@thumbcode/config';
9
import type {
10
  DeviceCodeResponse,
11
  DeviceFlowOptions,
12
  DeviceFlowState,
13
  StartFlowResult,
14
} from './types';
15

16
export class DeviceFlowHandler {
17
  /**
18
   * Start the Device Flow by requesting a device code from GitHub
19
   */
20
  async startDeviceFlow(
21
    options: DeviceFlowOptions,
22
    abortSignal?: AbortSignal,
23
    onSetState?: (state: DeviceFlowState) => void
24
  ): Promise<StartFlowResult> {
25
    const { clientId, scopes = GITHUB_OAUTH.scopes, onError } = options;
8✔
26

27
    if (!clientId) {
8✔
28
      const error = 'GitHub Client ID is required. Set EXPO_PUBLIC_GITHUB_CLIENT_ID in your environment.';
1✔
29
      onError?.(error);
1✔
30
      return { success: false, error };
1✔
31
    }
32

33
    onSetState?.('requesting_code');
7✔
34

35
    try {
7✔
36
      const response = await fetch(GITHUB_OAUTH.deviceCodeUrl, {
7✔
37
        method: 'POST',
38
        headers: {
39
          Accept: 'application/json',
40
          'Content-Type': 'application/x-www-form-urlencoded',
41
        },
42
        body: new URLSearchParams({
43
          client_id: clientId,
44
          scope: scopes,
45
        }).toString(),
46
        signal: abortSignal,
47
      });
48

49
      if (!response.ok) {
7✔
50
        const errorText = await response.text();
1✔
51
        const error = `Failed to request device code: ${response.status} ${errorText}`;
1✔
52
        onSetState?.('error');
1✔
53
        onError?.(error);
1✔
54
        return { success: false, error };
1✔
55
      }
56

57
      const data: DeviceCodeResponse = await response.json();
6✔
58

59
      onSetState?.('awaiting_user');
6✔
60
      options.onUserCode?.(data.user_code, data.verification_uri);
6✔
61

62
      return { success: true, data };
6✔
63
    } catch (error) {
NEW
64
      if (error instanceof Error && error.name === 'AbortError') {
×
NEW
65
        return { success: false, error: 'Request was cancelled' };
×
66
      }
67

NEW
68
      const errorMessage = error instanceof Error ? error.message : 'Failed to start device flow';
×
NEW
69
      onSetState?.('error');
×
NEW
70
      onError?.(errorMessage);
×
NEW
71
      return { success: false, error: errorMessage };
×
72
    }
73
  }
74
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc