Skillshub canva-debug-bundle
install
source · Clone the upstream repo
git clone https://github.com/ComeOnOliver/skillshub
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/ComeOnOliver/skillshub "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/jeremylongshore/claude-code-plugins-plus-skills/canva-debug-bundle" ~/.claude/skills/comeonoliver-skillshub-canva-debug-bundle && rm -rf "$T"
manifest:
skills/jeremylongshore/claude-code-plugins-plus-skills/canva-debug-bundle/SKILL.mdsource content
Canva Debug Bundle
Overview
Collect diagnostic information for Canva Connect API issues. Tests connectivity to
api.canva.com/rest/v1/*, validates OAuth tokens, checks rate limits, and packages evidence for support tickets.
Instructions
Step 1: Connectivity & Auth Check Script
#!/bin/bash # canva-debug.sh — Run with: bash canva-debug.sh set -euo pipefail TOKEN="${CANVA_ACCESS_TOKEN:-}" BUNDLE="canva-debug-$(date +%Y%m%d-%H%M%S)" mkdir -p "$BUNDLE" echo "=== Canva Connect API Debug Bundle ===" | tee "$BUNDLE/summary.txt" echo "Generated: $(date -u +%Y-%m-%dT%H:%M:%SZ)" | tee -a "$BUNDLE/summary.txt" echo "" >> "$BUNDLE/summary.txt" # 1. Check API reachability echo "--- API Connectivity ---" >> "$BUNDLE/summary.txt" HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \ -H "Authorization: Bearer ${TOKEN}" \ "https://api.canva.com/rest/v1/users/me") echo "GET /v1/users/me: HTTP $HTTP_CODE" | tee -a "$BUNDLE/summary.txt" # 2. Get user identity (if token valid) if [ "$HTTP_CODE" = "200" ]; then curl -s -H "Authorization: Bearer $TOKEN" \ "https://api.canva.com/rest/v1/users/me" | tee "$BUNDLE/user-identity.json" \ | python3 -m json.tool 2>/dev/null || true echo "Token: VALID" >> "$BUNDLE/summary.txt" else echo "Token: INVALID or EXPIRED (HTTP $HTTP_CODE)" >> "$BUNDLE/summary.txt" fi # 3. Check response headers for rate limit info echo "" >> "$BUNDLE/summary.txt" echo "--- Rate Limit Headers ---" >> "$BUNDLE/summary.txt" curl -s -D - -o /dev/null -H "Authorization: Bearer $TOKEN" \ "https://api.canva.com/rest/v1/designs?limit=1" 2>&1 \ | grep -iE "(x-ratelimit|retry-after|content-type|date)" \ >> "$BUNDLE/summary.txt" 2>/dev/null || echo "No rate limit headers" >> "$BUNDLE/summary.txt" # 4. DNS resolution echo "" >> "$BUNDLE/summary.txt" echo "--- DNS Resolution ---" >> "$BUNDLE/summary.txt" nslookup api.canva.com >> "$BUNDLE/summary.txt" 2>&1 || echo "nslookup not available" >> "$BUNDLE/summary.txt" # 5. TLS check echo "" >> "$BUNDLE/summary.txt" echo "--- TLS Handshake ---" >> "$BUNDLE/summary.txt" curl -sv "https://api.canva.com/rest/v1/users/me" 2>&1 \ | grep -E "(SSL|TLS|Connected)" >> "$BUNDLE/summary.txt" 2>/dev/null || true # 6. Environment info echo "" >> "$BUNDLE/summary.txt" echo "--- Environment ---" >> "$BUNDLE/summary.txt" echo "Node: $(node --version 2>/dev/null || echo 'not found')" >> "$BUNDLE/summary.txt" echo "OS: $(uname -s -r)" >> "$BUNDLE/summary.txt" echo "CANVA_CLIENT_ID: ${CANVA_CLIENT_ID:+[SET]}" >> "$BUNDLE/summary.txt" echo "CANVA_ACCESS_TOKEN: ${CANVA_ACCESS_TOKEN:+[SET]}" >> "$BUNDLE/summary.txt" # 7. Package bundle tar -czf "$BUNDLE.tar.gz" "$BUNDLE" echo "" echo "Bundle created: $BUNDLE.tar.gz"
Step 2: Programmatic Diagnostic
// src/canva/diagnostics.ts interface DiagnosticResult { check: string; status: 'pass' | 'fail' | 'warn'; details: string; durationMs: number; } async function runCanvaDiagnostics(token: string): Promise<DiagnosticResult[]> { const results: DiagnosticResult[] = []; // Check 1: API reachability const start1 = Date.now(); try { const res = await fetch('https://api.canva.com/rest/v1/users/me', { headers: { 'Authorization': `Bearer ${token}` }, }); results.push({ check: 'API Reachability', status: res.ok ? 'pass' : res.status === 401 ? 'fail' : 'warn', details: `HTTP ${res.status}`, durationMs: Date.now() - start1, }); } catch (e: any) { results.push({ check: 'API Reachability', status: 'fail', details: e.message, durationMs: Date.now() - start1 }); } // Check 2: Token validity const start2 = Date.now(); try { const res = await fetch('https://api.canva.com/rest/v1/users/me', { headers: { 'Authorization': `Bearer ${token}` }, }); if (res.ok) { const data = await res.json(); results.push({ check: 'Token Validity', status: 'pass', details: `user_id: ${data.team_user.user_id}`, durationMs: Date.now() - start2, }); } else { results.push({ check: 'Token Validity', status: 'fail', details: `HTTP ${res.status}`, durationMs: Date.now() - start2 }); } } catch (e: any) { results.push({ check: 'Token Validity', status: 'fail', details: e.message, durationMs: Date.now() - start2 }); } // Check 3: Design list (tests design:meta:read scope) const start3 = Date.now(); try { const res = await fetch('https://api.canva.com/rest/v1/designs?limit=1', { headers: { 'Authorization': `Bearer ${token}` }, }); results.push({ check: 'Scope: design:meta:read', status: res.ok ? 'pass' : res.status === 403 ? 'warn' : 'fail', details: res.ok ? 'Scope active' : `HTTP ${res.status} — scope may not be enabled`, durationMs: Date.now() - start3, }); } catch (e: any) { results.push({ check: 'Scope: design:meta:read', status: 'fail', details: e.message, durationMs: Date.now() - start3 }); } return results; } // Print report const results = await runCanvaDiagnostics(process.env.CANVA_ACCESS_TOKEN!); for (const r of results) { const icon = r.status === 'pass' ? 'OK' : r.status === 'warn' ? 'WARN' : 'FAIL'; console.log(`[${icon}] ${r.check}: ${r.details} (${r.durationMs}ms)`); }
Sensitive Data Handling
ALWAYS REDACT before sharing:
- Access tokens and refresh tokens
- Client secrets
- User IDs (if privacy-sensitive)
Safe to include:
- HTTP status codes and error messages
- Response headers (rate limit info)
- Latency measurements
- SDK/runtime versions
Error Handling
| Item | Purpose | Included |
|---|---|---|
HTTP status from | Auth validation | Yes |
| Rate limit headers | Throttling diagnosis | Yes |
| DNS resolution | Network path | Yes |
| TLS handshake | Certificate issues | Yes |
| Environment versions | Compatibility | Yes |
Resources
Next Steps
For rate limit issues, see
canva-rate-limits.