Add error reporting for GitHub rate limit errors

- Add specific error handling for GitHub API rate limit (403) errors
- Create RateLimitError with proper error name for identification
- Store last sync error and error time in settings for UI display
- Add error status display in autosync settings modal
- Show user-friendly error messages with GitHub token suggestion
- Clear error status on successful sync
- Update both GitHubJsonService and GitHubService with rate limit error handling

This provides better user feedback when GitHub API rate limits are exceeded
and guides users to set up a GitHub token for higher rate limits.
This commit is contained in:
Michel Roegl-Brunner
2025-10-24 22:23:59 +02:00
parent 7b4daf8754
commit ffef6313d4
5 changed files with 92 additions and 42 deletions

View File

@@ -48,7 +48,9 @@ export class AutoSyncService {
autoUpdateExisting: false,
notificationEnabled: false,
appriseUrls: [],
lastAutoSync: ''
lastAutoSync: '',
lastAutoSyncError: null,
lastAutoSyncErrorTime: null
};
const lines = envContent.split('\n');
@@ -93,6 +95,12 @@ export class AutoSyncService {
case 'LAST_AUTO_SYNC':
settings.lastAutoSync = value;
break;
case 'LAST_AUTO_SYNC_ERROR':
settings.lastAutoSyncError = value;
break;
case 'LAST_AUTO_SYNC_ERROR_TIME':
settings.lastAutoSyncErrorTime = value;
break;
}
}
}
@@ -109,7 +117,9 @@ export class AutoSyncService {
autoUpdateExisting: false,
notificationEnabled: false,
appriseUrls: [],
lastAutoSync: ''
lastAutoSync: '',
lastAutoSyncError: null,
lastAutoSyncErrorTime: null
};
}
}
@@ -149,7 +159,9 @@ export class AutoSyncService {
'AUTO_UPDATE_EXISTING': settings.autoUpdateExisting.toString(),
'NOTIFICATION_ENABLED': settings.notificationEnabled.toString(),
'APPRISE_URLS': JSON.stringify(settings.appriseUrls || []),
'LAST_AUTO_SYNC': settings.lastAutoSync || ''
'LAST_AUTO_SYNC': settings.lastAutoSync || '',
'LAST_AUTO_SYNC_ERROR': settings.lastAutoSyncError || '',
'LAST_AUTO_SYNC_ERROR_TIME': settings.lastAutoSyncErrorTime || ''
};
const existingKeys = new Set();
@@ -426,9 +438,13 @@ export class AutoSyncService {
await this.sendSyncNotification(results);
}
// Step 4: Update last sync time
// Step 4: Update last sync time and clear any previous errors
const lastSyncTime = this.safeToISOString(new Date());
const updatedSettings = { ...settings, lastAutoSync: lastSyncTime };
const updatedSettings = {
...settings,
lastAutoSync: lastSyncTime,
lastAutoSyncError: null // Clear any previous errors on successful sync
};
this.saveSettings(updatedSettings);
const duration = new Date().getTime() - startTime.getTime();
@@ -444,13 +460,22 @@ export class AutoSyncService {
} catch (error) {
console.error('Auto-sync execution failed:', error);
// Check if it's a rate limit error
const isRateLimitError = error instanceof Error && error.name === 'RateLimitError';
const errorMessage = error instanceof Error ? error.message : String(error);
// Send error notification if enabled
const settings = this.loadSettings();
if (settings.notificationEnabled && settings.appriseUrls?.length > 0) {
try {
const notificationTitle = isRateLimitError ? 'Auto-Sync Rate Limited' : 'Auto-Sync Failed';
const notificationMessage = isRateLimitError
? `GitHub API rate limit exceeded. Please set a GITHUB_TOKEN in your .env file for higher rate limits. Error: ${errorMessage}`
: `Auto-sync failed with error: ${errorMessage}`;
await appriseService.sendNotification(
'Auto-Sync Failed',
`Auto-sync failed with error: ${error instanceof Error ? error.message : String(error)}`,
notificationTitle,
notificationMessage,
settings.appriseUrls
);
} catch (notifError) {
@@ -458,10 +483,24 @@ export class AutoSyncService {
}
}
// Store the error in settings for UI display
const errorSettings = this.loadSettings();
const errorToStore = isRateLimitError
? `GitHub API rate limit exceeded. Please set a GITHUB_TOKEN in your .env file for higher rate limits.`
: errorMessage;
const updatedErrorSettings = {
...errorSettings,
lastAutoSyncError: errorToStore,
lastAutoSyncErrorTime: this.safeToISOString(new Date())
};
this.saveSettings(updatedErrorSettings);
return {
success: false,
message: error instanceof Error ? error.message : String(error),
error: error instanceof Error ? error.message : String(error)
message: errorToStore,
error: errorMessage,
isRateLimitError
};
} finally {
this.isRunning = false;

View File

@@ -37,16 +37,15 @@ export class GitHubService {
// Add GitHub token authentication if available
if (env.GITHUB_TOKEN) {
headers.Authorization = `token ${env.GITHUB_TOKEN}`;
console.log('Using GitHub token for API authentication');
} else {
console.log('No GitHub token found, using unauthenticated requests (lower rate limits)');
}
const response = await fetch(`${this.baseUrl}${endpoint}`, { headers });
if (!response.ok) {
if (response.status === 403) {
throw new Error(`GitHub API rate limit exceeded. Consider setting GITHUB_TOKEN for higher limits. Status: ${response.status} ${response.statusText}`);
const error = new Error(`GitHub API rate limit exceeded. Consider setting GITHUB_TOKEN for higher limits. Status: ${response.status} ${response.statusText}`);
error.name = 'RateLimitError';
throw error;
}
throw new Error(`GitHub API error: ${response.status} ${response.statusText}`);
}

View File

@@ -50,16 +50,15 @@ export class GitHubJsonService {
// Add GitHub token authentication if available
if (env.GITHUB_TOKEN) {
headers.Authorization = `token ${env.GITHUB_TOKEN}`;
console.log('Using GitHub token for API authentication');
} else {
console.log('No GitHub token found, using unauthenticated requests (lower rate limits)');
}
const response = await fetch(`${this.baseUrl!}${endpoint}`, { headers });
if (!response.ok) {
if (response.status === 403) {
throw new Error(`GitHub API rate limit exceeded. Consider setting GITHUB_TOKEN for higher limits. Status: ${response.status} ${response.statusText}`);
const error = new Error(`GitHub API rate limit exceeded. Consider setting GITHUB_TOKEN for higher limits. Status: ${response.status} ${response.statusText}`);
error.name = 'RateLimitError';
throw error;
}
throw new Error(`GitHub API error: ${response.status} ${response.statusText}`);
}
@@ -83,7 +82,9 @@ export class GitHubJsonService {
const response = await fetch(rawUrl, { headers });
if (!response.ok) {
if (response.status === 403) {
throw new Error(`GitHub rate limit exceeded while downloading ${filePath}. Consider setting GITHUB_TOKEN for higher limits. Status: ${response.status} ${response.statusText}`);
const error = new Error(`GitHub rate limit exceeded while downloading ${filePath}. Consider setting GITHUB_TOKEN for higher limits. Status: ${response.status} ${response.statusText}`);
error.name = 'RateLimitError';
throw error;
}
throw new Error(`Failed to download ${filePath}: ${response.status} ${response.statusText}`);
}