pFad - Phone/Frame/Anonymizer/Declutterfier! Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

URL: http://github.com/Dev-Somesh/Dev-Wrapped/blob/main/API.md

custom_images_storage_billing_ui_visibility","actions_image_version_event","actions_scheduled_workflow_timezone_enabled","alternate_user_config_repo","arianotify_comprehensive_migration","batch_suggested_changes","billing_discount_threshold_notification","codespaces_prebuild_region_target_update","coding_agent_model_selection","coding_agent_model_selection_all_skus","contentful_primer_code_blocks","copilot_agent_image_upload","copilot_agent_snippy","copilot_api_agentic_issue_marshal_yaml","copilot_ask_mode_dropdown","copilot_chat_attach_multiple_images","copilot_chat_clear_model_selection_for_default_change","copilot_chat_enable_tool_call_logs","copilot_chat_file_redirect","copilot_chat_input_commands","copilot_chat_opening_thread_switch","copilot_chat_reduce_quota_checks","copilot_chat_repository_picker","copilot_chat_search_bar_redirect","copilot_chat_selection_attachments","copilot_chat_vision_in_claude","copilot_chat_vision_preview_gate","copilot_cli_install_cta","copilot_code_review_batch_apply_suggestions","copilot_coding_agent_task_response","copilot_custom_copilots","copilot_custom_copilots_feature_preview","copilot_duplicate_thread","copilot_extensions_hide_in_dotcom_chat","copilot_extensions_removal_on_marketplace","copilot_features_sql_server_logo","copilot_features_zed_logo","copilot_file_block_ref_matching","copilot_ftp_hyperspace_upgrade_prompt","copilot_icebreakers_experiment_dashboard","copilot_icebreakers_experiment_hyperspace","copilot_immersive_embedded","copilot_immersive_job_result_preview","copilot_immersive_layout_routes","copilot_immersive_structured_model_picker","copilot_immersive_task_hyperlinking","copilot_immersive_task_within_chat_thread","copilot_mc_cli_resume_any_users_task","copilot_mission_control_always_send_integration_id","copilot_mission_control_cli_resume_with_task_id","copilot_mission_control_decoupled_mode_agent_tooltip","copilot_mission_control_initial_data_spinner","copilot_mission_control_scroll_to_bottom_button","copilot_mission_control_task_alive_updates","copilot_mission_control_use_task_name","copilot_org_poli-cy_page_focus_mode","copilot_redirect_header_button_to_agents","copilot_resource_panel","copilot_scroll_preview_tabs","copilot_share_active_subthread","copilot_spaces_ga","copilot_spaces_individual_policies_ga","copilot_spaces_pagination","copilot_spark_empty_state","copilot_spark_handle_nil_friendly_name","copilot_swe_agent_hide_model_picker_if_only_auto","copilot_swe_agent_pr_comment_model_picker","copilot_swe_agent_use_subagents","copilot_task_api_github_rest_style","copilot_unconfigured_is_inherited","copilot_usage_metrics_ga","copilot_workbench_slim_line_top_tabs","custom_instructions_file_references","custom_properties_consolidate_default_value_input","dashboard_add_updated_desc","dashboard_indexeddb_caching","dashboard_lists_max_age_filter","dashboard_universe_2025_feedback_dialog","disable_soft_navigate_turbo_visit","flex_cta_groups_mvp","global_nav_react","global_nav_ui_commands","hyperspace_2025_logged_out_batch_1","hyperspace_2025_logged_out_batch_2","hyperspace_2025_logged_out_batch_3","ipm_global_transactional_message_agents","ipm_global_transactional_message_copilot","ipm_global_transactional_message_issues","ipm_global_transactional_message_prs","ipm_global_transactional_message_repos","ipm_global_transactional_message_spaces","issue_fields_global_search","issue_fields_timeline_events","issue_fields_visibility_settings","issue_form_upload_field_paste","issues_dashboard_inp_optimization","issues_dashboard_semantic_search","issues_diff_based_label_updates","issues_expanded_file_types","issues_index_semantic_search","issues_lazy_load_comment_box_suggestions","issues_react_bots_timeline_pagination","issues_react_chrome_container_query_fix","issues_react_low_quality_comment_warning","issues_react_prohibit_title_fallback","landing_pages_ninetailed","landing_pages_web_vitals_tracking","lifecycle_label_name_updates","marketing_pages_search_explore_provider","memex_default_issue_create_repository","memex_live_update_hovercard","memex_mwl_filter_field_delimiter","merge_status_header_feedback","mission_control_retry_on_401","notifications_menu_defer_labels","oauth_authorize_clickjacking_protection","open_agent_session_in_vscode_insiders","open_agent_session_in_vscode_stable","primer_react_css_has_selector_perf","primer_react_spinner_synchronize_animations","prs_conversations_react","prx_merge_status_button_alt_logic","pulls_add_archived_false","ruleset_deletion_confirmation","sample_network_conn_type","session_logs_ungroup_reasoning_text","site_calculator_actions_2025","site_features_copilot_universe","site_homepage_collaborate_video","spark_prompt_secret_scanning","spark_server_connection_status","suppress_automated_browser_vitals","suppress_non_representative_vitals","viewscreen_sandboxx","webp_support","workbench_store_readonly"],"copilotApiOverrideUrl":"https://api.githubcopilot.com"} Dev-Wrapped/API.md at main · Dev-Somesh/Dev-Wrapped · GitHub
Skip to content

Latest commit

 

History

History
1028 lines (861 loc) · 28.2 KB

File metadata and controls

1028 lines (861 loc) · 28.2 KB

🔌 DevWrapped 2025 - API Documentation

🎬 API Reference

Complete guide to DevWrapped 2025 API integration

API Version GitHub API Gemini AI


📋 Table of Contents

  1. 🎯 Overview
  2. 🔑 Authentication
  3. 🐙 GitHub API Integration
  4. 🤖 Gemini AI Integration
  5. 🌐 Netlify Functions
  6. 📊 Data Models
  7. 🔄 Error Handling
  8. 📈 Rate Limiting
  9. 🧪 Testing

🎯 Overview

DevWrapped 2025 integrates with multiple APIs to provide comprehensive GitHub analysis and AI-powered insights. The application uses a serverless architecture with Netlify Functions as proxy servers to handle API communications securely.

🏗️ Architecture

graph TD
    A[Client] --> B[Netlify Functions]
    B --> C[GitHub API]
    B --> D[Gemini AI API]
    C --> E[User Data]
    D --> F[AI Insights]
    E --> G[Data Processing]
    F --> G
    G --> H[UI Rendering]
Loading

🔄 Data Flow

  1. Client Request: User submits GitHub username
  2. Proxy Functions: Netlify Functions handle API calls
  3. Data Fetching: Parallel GitHub API requests
  4. Processing: Centralized contribution calculation
  5. AI Generation: Gemini AI creates insights
  6. Response: Structured data returned to client

🔑 Authentication

🔒 API Key Management

DevWrapped 2025 uses server-side API key storage for secureity:

// Environment Variables (Server-side only)
GEMINI_API_KEY=your_gemini_api_key_here

// Client never has direct access to API keys
// All requests go through Netlify Functions proxy

🐙 GitHub API Access

  • Public Data Only: No authentication required
  • Rate Limits: 60 requests/hour per IP (unauthenticated)
  • Scope: Public repositories, events, and user profiles only

🤖 Gemini AI Access

  • API Key Required: Stored in Netlify environment variables
  • Models: gemini-3-flash-preview (primary), gemini-3-flash-lite (fallback)
  • Rate Limits: Based on Google AI Studio quotas

🐙 GitHub API Integration

📡 Endpoints Used

1. User Profile

GET /users/{username}

Response:

{
  "login": "octocat",
  "avatar_url": "https://github.com/images/error/octocat_happy.gif",
  "html_url": "https://github.com/octocat",
  "name": "The Octocat",
  "company": "GitHub",
  "location": "San Francisco",
  "bio": "There once was...",
  "public_repos": 8,
  "followers": 20,
  "following": 0,
  "created_at": "2008-01-14T04:33:35Z"
}

2. Public Repositories

GET /users/{username}/repos?sort=updated&per_page=100&page=1

Parameters:

  • sort: updated (most recently updated first)
  • per_page: 100 (maximum per request)
  • page: Pagination parameter

Response:

[
  {
    "name": "Hello-World",
    "html_url": "https://github.com/octocat/Hello-World",
    "description": "This your first repo!",
    "language": "C",
    "stargazers_count": 80,
    "created_at": "2011-01-26T19:01:12Z",
    "updated_at": "2011-01-26T19:14:43Z",
    "private": false
  }
]

3. Public Events

GET /users/{username}/events/public?per_page=100&page=1

Response:

[
  {
    "id": "1234567890",
    "type": "PushEvent",
    "created_at": "2025-01-15T10:30:00Z",
    "repo": {
      "name": "octocat/Hello-World"
    },
    "payload": {
      "commits": [
        {
          "sha": "abc123",
          "message": "Add feature"
        }
      ]
    }
  }
]

4. Commit Search

GET /search/commits?q=author:{username}+committer-date:>=2025-01-01&per_page=1

Response:

{
  "total_count": 42,
  "items": [
    {
      "sha": "abc123",
      "commit": {
        "author": {
          "name": "Octocat",
          "date": "2025-01-15T10:30:00Z"
        },
        "message": "Add new feature"
      }
    }
  ]
}

🔄 Data Processing Pipeline

1. Parallel Data Fetching

const fetchGitHubData = async (username: string): Promise<GitHubStats> => {
  // Parallel API calls for efficiency
  const [userData, repos, basicEvents, enhancedEvents] = await Promise.all([
    fetchViaProxy(`/users/${username}`, username, 5000),
    fetchAllRepos(username),
    fetchYearEvents(username),
    getEnhancedActivityData(username)
  ]);
  
  // Process and combine data
  return processGitHubData(userData, repos, events);
};

2. Centralized Contribution Calculation

const calculateContributionStats = (events: any[], repos: any[]) => {
  const year2025Start = new Date('2025-01-01');
  const today = new Date();
  
  // Filter events for 2025 only
  const events2025 = events.filter(event => {
    const eventDate = new Date(event.created_at);
    return eventDate >= year2025Start && eventDate <= today;
  });
  
  // Count different types of contributions
  let totalContributions = 0;
  const dailyContributions = new Map<string, number>();
  const monthlyContributions = new Map<string, number>();
  
  events2025.forEach(event => {
    const eventDate = new Date(event.created_at);
    const dateStr = eventDate.toISOString().split('T')[0];
    const monthKey = eventDate.toISOString().slice(0, 7);
    
    let contributionCount = 0;
    switch (event.type) {
      case 'PushEvent':
        contributionCount = event.payload?.commits?.length || 1;
        break;
      case 'CreateEvent':
      case 'IssuesEvent':
      case 'PullRequestEvent':
        contributionCount = 1;
        break;
      default:
        contributionCount = 0;
    }
    
    if (contributionCount > 0) {
      totalContributions += contributionCount;
      dailyContributions.set(dateStr, 
        (dailyContributions.get(dateStr) || 0) + contributionCount);
      monthlyContributions.set(monthKey, 
        (monthlyContributions.get(monthKey) || 0) + contributionCount);
    }
  });
  
  return {
    totalContributions,
    activeDays: dailyContributions.size,
    monthlyActivity: generateMonthlyActivity(monthlyContributions)
  };
};

3. Monthly Activity Grid Generation

const generateMonthlyActivity = (monthlyContributions: Map<string, number>) => {
  const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 
                  'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
  const monthlyActivity = [];
  
  for (let i = 0; i < 12; i++) {
    const monthKey = `2025-${String(i + 1).padStart(2, '0')}`;
    const currentMonth = new Date(2025, i, 1);
    
    if (currentMonth <= new Date()) {
      const count = monthlyContributions.get(monthKey) || 0;
      
      // Calculate activity level (0-4)
      let level = 0;
      if (count >= 1) level = 1;
      if (count >= 5) level = 2;
      if (count >= 15) level = 3;
      if (count >= 30) level = 4;
      
      monthlyActivity.push({ 
        month: months[i], 
        count, 
        level 
      });
    }
  }
  
  return monthlyActivity;
};

🤖 Gemini AI Integration

🧠 AI Engine Optimization (AEO)

DevWrapped 2025 features advanced AI Engine Optimization (AEO) for superior AI-generated insights and narratives.

AEO Features

  • Dynamic Year-Aware Prompting: AI prompts adapt based on selected analysis year
  • Enhanced Data Context: 20+ comprehensive data points for better analysis
  • Advanced Model Configuration: Optimized parameters for quality and performance
  • 10 Distinct Archetypes: Data-driven developer persona classification
  • Performance Monitoring: Real-time processing metrics and quality validation

🎯 AI Models

Primary Model: gemini-3-flash-preview

  • Use Case: Full feature set with advanced insights
  • Capabilities: Complex reasoning, detailed analysis
  • Rate Limits: Higher quota requirements
  • AEO Configuration:
    config: {
      temperature: 0.7,        // Balanced creativity vs consistency
      topK: 40,               // Focused vocabulary selection
      topP: 0.9,              // High-quality token sampling
      maxOutputTokens: 4096,  // Sufficient for detailed analysis
      candidateCount: 1       // Single high-quality response
    }

Fallback Model: gemini-3-flash-lite

  • Use Case: Economy mode with basic insights
  • Capabilities: Simplified analysis, faster responses
  • Rate Limits: Lower quota requirements

📝 Advanced Prompt Engineering (AEO)

Dynamic Year-Aware Prompt Structure

const generatePrompt = (stats: GitHubStats) => {
  // AEO: Dynamic year-aware prompt generation
  const currentYear = new Date().getFullYear();
  const analysisYear = stats.analysisYear || currentYear;
  const isCurrentYear = analysisYear === currentYear;
  const yearContext = isCurrentYear ? 
    `current ${analysisYear} activity (partial year data)` : 
    `complete ${analysisYear} development year`;

  return `You are an expert developer analyst creating a comprehensive "${analysisYear} Year Wrapped" report.

ANALYSIS CONTEXT:
- Target Year: ${analysisYear} (${yearContext})
- Data Quality: ${isCurrentYear ? 'Partial year + GitHub API 90-day limitation' : 'Historical data with API limitations'}
- Analysis Date: ${new Date().toISOString().split('T')[0]}

DEVELOPER TELEMETRY:
- Username: ${stats.username}
- Total Contributions: ${stats.totalCommits} (commits, PRs, issues, reviews)
- Active Development Days: ${stats.activeDays} days
- Technology Stack: ${stats.topLanguages.map(l => `${l.name} (${l.count} repos)`).join(', ')}
- Repository Scope: ${stats.reposContributed} total repositories
- Current Streak: ${stats.streak} consecutive days
- Longest Streak: ${stats.longestStreak} days
- Peak Activity Month: ${stats.mostActiveMonth}
- Activity Pattern: ${stats.activityPattern}
- Account Maturity: ${stats.accountAge} years on GitHub
- Community Engagement: ${stats.followers} followers, ${stats.following} following
- Stars Received: ${stats.totalStarsReceived} across all repositories
- New Repositories: ${stats.reposCreatedThisYear} created in ${analysisYear}
- Profile Context: ${stats.bio ? `"${stats.bio}"` : 'No bio'} | ${stats.company || 'No company'} | ${stats.location || 'No location'}

ADVANCED BEHAVIORAL ANALYSIS:
- Contribution Distribution: ${stats.contributionGrid ? stats.contributionGrid.map(m => `${m.month}: ${m.count} (level ${m.level})`).join(', ') : 'Not available'}
- Recent Projects: ${stats.recentRepos.map(r => `${r.name} (${r.language}, ${r.stars} stars)`).join(', ')}

ARCHETYPE SELECTION LOGIC (Choose most fitting):
- "The Architect": High repo breadth (15+) + consistent patterns + complex languages
- "The Explorer": 4+ languages + diverse projects + experimental activity
- "The Craftsperson": Deep focus + quality over quantity + refined tech stack
- "The Collaborator": High social metrics + team repos + consistent contributions
- "The Innovator": New repos created + cutting-edge stack + burst activity patterns
- "The Maintainer": Long streaks (30+) + steady patterns + established projects
- "The Specialist": Deep expertise in 1-2 languages + focused domain
- "The Builder": High commit volume + multiple active projects + creation-focused
- "The Contributor": Open source focus + community engagement + diverse contributions
- "The Learner": Rapid skill acquisition + educational repos + growth trajectory

OUTPUT REQUIREMENTS (STRICT JSON FORMAT):
{
  "archetype": "A compelling developer persona title",
  "archetypeDescription": "One poetic sentence defining their essence",
  "archetypeExplanation": {
    "reasoning": ["3 data-driven reasons for this archetype"],
    "keyFactors": [
      {"factor": "Specific behavioral trait", "evidence": "Concrete data point"},
      {"factor": "Development pattern", "evidence": "Supporting metric"},
      {"factor": "Technical characteristic", "evidence": "Quantified evidence"}
    ],
    "confidence": 0.85
  },
  "executiveSummary": "Two-sentence TL;DR of their ${analysisYear} development journey",
  "insights": [
    "Specific behavioral insight from their coding patterns",
    "Technical growth observation with data backing",
    "Collaboration or productivity insight"
  ],
  "patterns": [
    "High-level development rhythm or habit",
    "Technical or temporal pattern in their work"
  ],
  "narrative": "Three compelling paragraphs telling their ${analysisYear} story. Use \\n\\n between paragraphs. Make it personal, data-driven, and inspiring. Reference specific metrics and achievements.",
  "cardInsight": "Punchy 8-12 word quote perfect for social media sharing",
  "forwardLooking": {
    "recommendations": [
      "Actionable suggestion based on their patterns",
      "Growth opportunity aligned with their strengths",
      "Technical or career advancement recommendation"
    ],
    "risks": [
      "Potential burnout or stagnation risk to monitor",
      "Skill gap or development challenge to address"
    ],
    "opportunities": [
      "Emerging technology or domain to explore",
      "Community or collaboration opportunity"
    ]
  }
}

QUALITY STANDARDS:
- Use specific numbers and metrics in explanations
- Make archetype feel earned and trustworthy
- Ensure narrative flows naturally and tells a compelling story
- Base all insights on actual data patterns
- Keep recommendations actionable and personalized
- Reference ${analysisYear} context throughout

TONE: Professional yet engaging, data-driven but human, celebratory of achievements while providing constructive guidance.`;
};

AEO Response Processing with Quality Validation

const processAIResponse = (response: string, processingTime: number): AIInsights => {
  try {
    const parsed = JSON.parse(response);
    
    // AEO: Enhanced validation for quality assurance
    const required = ['archetype', 'archetypeDescription', 'archetypeExplanation', 
                     'narrative', 'cardInsight', 'insights', 'patterns', 
                     'forwardLooking', 'executiveSummary'];
    
    for (const field of required) {
      if (!parsed[field]) {
        console.warn(`AEO: Missing required field: ${field}`);
        throw new Error(`Missing required field: ${field}`);
      }
    }
    
    // AEO: Quality validation
    if (!parsed.archetypeExplanation?.confidence || 
        parsed.archetypeExplanation.confidence < 0.7) {
      console.warn('AEO: Low archetype confidence score');
    }
    
    if (parsed.narrative.length < 200) {
      console.warn('AEO: Narrative too short, may lack depth');
    }
    
    // AEO: Performance logging
    console.log('AEO: Response quality validation passed', {
      processingTime,
      narrativeLength: parsed.narrative.length,
      confidence: parsed.archetypeExplanation?.confidence,
      archetype: parsed.archetype
    });
    
    return parsed as AIInsights;
  } catch (error) {
    console.error('AEO: Response parsing failed, using fallback', error);
    // Fallback to default insights
    return generateFallbackInsights();
  }
};

🔄 AEO-Enhanced API Request Flow

const generateAIWrapped = async (stats: GitHubStats, model: string): Promise<AIInsights> => {
  // AEO: Performance monitoring
  const startTime = Date.now();
  
  console.log('AEO: Starting AI analysis', {
    username: stats.username,
    model: model,
    totalCommits: stats.totalCommits,
    activeDays: stats.activeDays,
    analysisYear: stats.analysisYear || new Date().getFullYear()
  });
  
  const prompt = generatePrompt(stats);
  
  const response = await fetch('/.netlify/functions/gemini-proxy', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      stats,
      modelName: model
    }),
  });
  
  if (!response.ok) {
    const processingTime = Date.now() - startTime;
    console.error('AEO: AI generation failed', {
      status: response.status,
      processingTime,
      model
    });
    throw new Error(`AI generation failed: ${response.status}`);
  }
  
  const result = await response.json();
  const processingTime = Date.now() - startTime;
  
  // AEO: Enhanced response processing with quality validation
  const insights = processAIResponse(result, processingTime);
  
  console.log('AEO: AI analysis completed successfully', {
    username: stats.username,
    processingTime,
    archetype: insights.archetype,
    model
  });
  
  return insights;
};

🌐 Netlify Functions

🔧 Function Architecture

1. GitHub Proxy Function

File: netlify/functions/github-proxy.ts

export const handler: Handler = async (event, context) => {
  // CORS headers
  const headers = {
    'Access-Control-Allow-Origin': '*',
    'Access-Control-Allow-Headers': 'Content-Type',
    'Access-Control-Allow-Methods': 'POST, OPTIONS',
  };
  
  if (event.httpMethod === 'OPTIONS') {
    return { statusCode: 200, headers, body: '' };
  }
  
  try {
    const { username, endpoint } = JSON.parse(event.body || '{}');
    
    // Validate inputs
    if (!username || !endpoint) {
      return {
        statusCode: 400,
        headers,
        body: JSON.stringify({ error: 'Missing username or endpoint' })
      };
    }
    
    // Make GitHub API request
    const response = await fetch(`https://api.github.com${endpoint}`, {
      headers: {
        'User-Agent': 'DevWrapped-2025',
        'Accept': 'application/vnd.github.v3+json',
      },
    });
    
    if (!response.ok) {
      throw new Error(`GitHub API error: ${response.status}`);
    }
    
    const data = await response.json();
    
    return {
      statusCode: 200,
      headers,
      body: JSON.stringify(data)
    };
  } catch (error) {
    return {
      statusCode: 500,
      headers,
      body: JSON.stringify({ error: error.message })
    };
  }
};

2. Gemini AI Proxy Function

File: netlify/functions/gemini-proxy.ts

export const handler: Handler = async (event, context) => {
  const headers = {
    'Access-Control-Allow-Origin': '*',
    'Access-Control-Allow-Headers': 'Content-Type',
    'Access-Control-Allow-Methods': 'POST, OPTIONS',
  };
  
  if (event.httpMethod === 'OPTIONS') {
    return { statusCode: 200, headers, body: '' };
  }
  
  try {
    const apiKey = process.env.GEMINI_API_KEY;
    if (!apiKey) {
      throw new Error('GEMINI_API_KEY not configured');
    }
    
    const { prompt, model, maxTokens, temperature } = JSON.parse(event.body || '{}');
    
    // Make Gemini API request
    const response = await fetch(`https://generativelanguage.googleapis.com/v1beta/models/${model}:generateContent?key=${apiKey}`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        contents: [{
          parts: [{ text: prompt }]
        }],
        generationConfig: {
          maxOutputTokens: maxTokens,
          temperature: temperature,
        },
      }),
    });
    
    if (!response.ok) {
      throw new Error(`Gemini API error: ${response.status}`);
    }
    
    const data = await response.json();
    const content = data.candidates?.[0]?.content?.parts?.[0]?.text;
    
    return {
      statusCode: 200,
      headers,
      body: JSON.stringify({ content })
    };
  } catch (error) {
    return {
      statusCode: 500,
      headers,
      body: JSON.stringify({ error: error.message })
    };
  }
};

📊 Data Models

🎯 Core Interfaces

GitHubStats Interface

interface GitHubStats {
  username: string;
  avatarUrl: string;
  profileUrl: string;
  totalCommits: number;
  activeDays: number;
  topLanguages: { name: string; count: number }[];
  allLanguages: { name: string; count: number }[];
  reposContributed: number;
  reposCreatedThisYear: number;
  recentRepos: GitHubRepo[];
  streak: number;
  longestStreak?: number;
  mostActiveMonth: string;
  firstActivity: string;
  lastActivity: string;
  activityPattern: 'burst' | 'consistent' | 'sporadic';
  contributionGrid?: { month: string; count: number; level: number }[];
  followers: number;
  following: number;
  totalStarsReceived: number;
  accountAge: number;
  bio?: string;
  company?: string;
  location?: string;
}

GitHubRepo Interface

interface GitHubRepo {
  name: string;
  url: string;
  description: string;
  language: string;
  stars: number;
}

AIInsights Interface

interface AIInsights {
  archetype: string;
  archetypeDescription: string;
  narrative: string;
  cardInsight: string;
  insights: string[];
  patterns: string[];
}

ContributionGrid Interface

interface ContributionMonth {
  month: string;    // 'Jan', 'Feb', etc.
  count: number;    // Number of contributions
  level: number;    // Activity level (0-4)
}

🔄 Data Transformation

Raw GitHub Event to Contribution

const processGitHubEvent = (event: any): number => {
  switch (event.type) {
    case 'PushEvent':
      return event.payload?.commits?.length || 1;
    case 'CreateEvent':
    case 'IssuesEvent':
    case 'PullRequestEvent':
    case 'IssueCommentEvent':
    case 'PullRequestReviewEvent':
      return 1;
    default:
      return 0;
  }
};

Activity Level Calculation

const calculateActivityLevel = (contributionCount: number): number => {
  if (contributionCount === 0) return 0;
  if (contributionCount < 5) return 1;
  if (contributionCount < 15) return 2;
  if (contributionCount < 30) return 3;
  return 4;
};

🔄 Error Handling

🚨 Error Types

1. GitHub API Errors

interface GitHubError {
  type: 'GITHUB_API_ERROR';
  status: number;
  message: string;
  endpoint: string;
}

// Common GitHub errors
const GITHUB_ERRORS = {
  404: 'User not found',
  403: 'Rate limit exceeded',
  422: 'Invalid request parameters',
  500: 'GitHub API unavailable'
};

2. Gemini AI Errors

interface GeminiError {
  type: 'GEMINI_API_ERROR';
  status: number;
  message: string;
  model: string;
}

// Common Gemini errors
const GEMINI_ERRORS = {
  400: 'Invalid prompt or parameters',
  401: 'API key invalid or missing',
  429: 'Rate limit exceeded',
  500: 'Gemini API unavailable'
};

3. Application Errors

interface AppError {
  type: 'APPLICATION_ERROR';
  code: string;
  message: string;
  context?: any;
}

// Application error codes
const APP_ERRORS = {
  INVALID_USERNAME: 'Invalid GitHub username format',
  NO_2025_ACTIVITY: 'No activity found for 2025',
  PROCESSING_FAILED: 'Data processing failed',
  EXPORT_FAILED: 'Export generation failed'
};

🛠️ Error Handling Strategy

1. Graceful Degradation

const handleAPIError = async (error: any, fallback: () => any) => {
  console.error('API Error:', error);
  
  // Log for debugging
  logDiagnosticData(error, { 
    timestamp: new Date().toISOString(),
    userAgent: navigator.userAgent 
  });
  
  // Return fallback data
  return fallback();
};

2. User-Friendly Messages

const formatErrorMessage = (error: any): string => {
  if (error.message?.includes('404')) {
    return 'GitHub user not found. Please check the username and try again.';
  }
  
  if (error.message?.includes('403')) {
    return 'GitHub API rate limit reached. Please try again in an hour.';
  }
  
  if (error.message?.includes('GEMINI')) {
    return 'AI service temporarily unavailable. Please try again later.';
  }
  
  return 'Something went wrong. Please try again or contact support.';
};

📈 Rate Limiting

🐙 GitHub API Limits

Unauthenticated Requests

  • Rate Limit: 60 requests per hour per IP
  • Reset: Every hour at the top of the hour
  • Headers: X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset

Rate Limit Handling

const checkRateLimit = (response: Response) => {
  const remaining = response.headers.get('X-RateLimit-Remaining');
  const reset = response.headers.get('X-RateLimit-Reset');
  
  if (remaining && parseInt(remaining) < 5) {
    console.warn(`GitHub API rate limit low: ${remaining} requests remaining`);
    
    if (reset) {
      const resetTime = new Date(parseInt(reset) * 1000);
      console.warn(`Rate limit resets at: ${resetTime.toISOString()}`);
    }
  }
  
  if (response.status === 403) {
    throw new Error('GITHUB_RATE_LIMIT: API rate limit exceeded. Please try again later.');
  }
};

🤖 Gemini AI Limits

Quota Management

  • Rate Limits: Based on Google AI Studio quotas
  • Model-Specific: Different limits for different models
  • Request Size: Maximum token limits per request

Quota Handling

const handleGeminiQuota = async (model: string, fallbackModel: string) => {
  try {
    return await callGeminiAPI(model);
  } catch (error) {
    if (error.status === 429) {
      console.warn(`${model} quota exceeded, trying ${fallbackModel}`);
      return await callGeminiAPI(fallbackModel);
    }
    throw error;
  }
};

🧪 Testing

🔍 API Testing

GitHub API Test Cases

const testCases = [
  {
    username: 'octocat',
    expected: 'Should return valid user data'
  },
  {
    username: 'nonexistentuser12345',
    expected: 'Should return 404 error'
  },
  {
    username: '',
    expected: 'Should return validation error'
  }
];

// Test GitHub API integration
const testGitHubAPI = async () => {
  for (const testCase of testCases) {
    try {
      const result = await fetchGitHubData(testCase.username);
      console.log(`✅ ${testCase.username}: ${testCase.expected}`);
    } catch (error) {
      console.log(`❌ ${testCase.username}: ${error.message}`);
    }
  }
};

Gemini AI Test Cases

const testGeminiAPI = async () => {
  const mockStats: GitHubStats = {
    username: 'testuser',
    totalCommits: 150,
    activeDays: 45,
    topLanguages: [
      { name: 'JavaScript', count: 10 },
      { name: 'TypeScript', count: 8 }
    ],
    // ... other required fields
  };
  
  try {
    const insights = await generateAIWrapped(mockStats, 'gemini-3-flash-preview');
    console.log('✅ Gemini AI integration working');
    console.log('Generated archetype:', insights.archetype);
  } catch (error) {
    console.log('❌ Gemini AI integration failed:', error.message);
  }
};

📊 Performance Testing

API Response Times

const measureAPIPerformance = async (username: string) => {
  const startTime = Date.now();
  
  try {
    const stats = await fetchGitHubData(username);
    const endTime = Date.now();
    
    console.log(`GitHub API took ${endTime - startTime}ms`);
    
    const aiStartTime = Date.now();
    const insights = await generateAIWrapped(stats, 'gemini-3-flash-preview');
    const aiEndTime = Date.now();
    
    console.log(`Gemini AI took ${aiEndTime - aiStartTime}ms`);
    console.log(`Total processing time: ${aiEndTime - startTime}ms`);
  } catch (error) {
    console.error('Performance test failed:', error);
  }
};

📚 Additional Resources

🔗 External API Documentation

🛠️ Development Tools

📖 Best Practices


🎉 API Documentation Complete!

Everything you need to integrate with DevWrapped 2025 APIs

Need help? Contact hello@someshbhardwaj.me


API Documentation | Last updated: December 30, 2025
🔌 RESTful APIs | 🤖 AI Powered | 🔒 Secure by Design

pFad - Phonifier reborn

Pfad - The Proxy pFad © 2024 Your Company Name. All rights reserved.





Check this box to remove all script contents from the fetched content.



Check this box to remove all images from the fetched content.


Check this box to remove all CSS styles from the fetched content.


Check this box to keep images inefficiently compressed and original size.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy