Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion packages/db/src/repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1964,9 +1964,11 @@ function sanitiseSyncFailure(error: unknown): string {

function classifySyncFailure(error: unknown): SyncFailureClassification {
if (hasSyncFailureClassification(error)) return error.classification
// A body that is not JSON is an unexpected answer from the server, not a rejected login.
if (error instanceof SyntaxError) return 'upstream_response'
const message = error instanceof Error ? error.message.toLowerCase() : ''
if (message.includes('encryption') || message.includes('configuration') || message.includes('required before')) return 'configuration'
if (message.includes('unauthor') || message.includes('forbidden') || message.includes('credential') || message.includes('token')) return 'authentication'
if (message.includes('unauthor') || message.includes('forbidden') || message.includes('credential') || (message.includes('plex') && message.includes('token'))) return 'authentication'
if (message.includes('timeout') || message.includes('network') || message.includes('connect') || message.includes('unavailable')) return 'upstream_unavailable'
if (message.includes('plex') || message.includes('response') || message.includes('parse')) return 'upstream_response'
return 'unknown'
Expand Down
34 changes: 34 additions & 0 deletions packages/db/src/sync-failure-label.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { describe, expect, it } from 'vitest'
import { failSyncRun } from './repository.js'
import type { Database } from './repository.js'

// failSyncRun writes one tagged-template UPDATE; the second interpolated value is the stored summary.
async function storedSummary(error: unknown): Promise<string> {
let summary = ''
const database = (async (_strings: TemplateStringsArray, ...values: unknown[]) => {
summary = String(values[0])
return []
}) as unknown as Database
await failSyncRun(database, 'run-1', error)
return summary
}

describe('failSyncRun labels', () => {
it('records an unexpected non-JSON body as an unexpected response, not a rejected login', async () => {
expect(await storedSummary(new SyntaxError('Unexpected token < in JSON at position 0'))).toBe(
'upstream_response: Plex returned an unexpected response.',
)
})

it('does not call a non-Plex error that mentions a token an authentication failure', async () => {
expect(await storedSummary(new Error('invalid input syntax for type uuid: bad token'))).toBe(
'unknown: The sync did not complete.',
)
})

it('still labels a Plex token problem as authentication', async () => {
expect(await storedSummary(new Error('Plex token was unauthorized'))).toBe(
'authentication: Plex authentication was rejected.',
)
})
})
Loading