fix(stalker): prioritize response status semantics

This commit is contained in:
4gray committed 2026-07-27 03:56:27 +02:00
1 parent 604d2aca3e
commit 847d98f035
2 files changed
+65 -15

No files matched your search

@@ -156,6 +156,49 @@ describe('Stalker response classifier', () => {
});
});
it.each([
[
429,
{
kind: 'failure',
reason: 'rate-limited',
},
],
[
503,
{
kind: 'failure',
reason: 'portal-unavailable',
},
],
[404, { kind: 'none' }],
])(
'gives HTTP status %i precedence over an authorization error body',
(httpStatus, expected) => {
expect(
classifyStalkerResponseFailure({
httpStatus,
value: { js: { error: 'Authorization failed' } },
})
).toEqual(expected);
}
);
it.each([
['Authorization failed', { kind: 'token-rejected' }],
[
'Access denied',
{ kind: 'failure', reason: 'account-access-denied' },
],
])('classifies the canonical error %s on HTTP 403', (error, expected) => {
expect(
classifyStalkerResponseFailure({
httpStatus: 403,
value: { js: { error } },
})
).toEqual(expected);
});
it('ignores a normal raw JSON body when a parsed response value exists', () => {
expect(
classifyStalkerResponseFailure({
@@ -149,15 +149,34 @@ export function classifyStalkerResponseFailure(
| { kind: 'none' }
| { kind: 'token-rejected' }
| StalkerClassifierFailure {
const bodyError = extractBodyError(input.value, input.rawBody);
const bodyHasErrorIndicator = hasBodyErrorIndicator(input.value);
if (input.httpStatus === 403 && looksLikePortalProtection(input.rawBody)) {
return {
kind: 'failure',
reason: STALKER_FAILURE_REASONS.PortalProtectionBlocked,
};
}
if (input.httpStatus === 401 || bodyError === 'Authorization failed') {
if (input.httpStatus === 401) {
return { kind: 'token-rejected' };
}
if (input.httpStatus === 429) {
return {
kind: 'failure',
reason: STALKER_FAILURE_REASONS.RateLimited,
};
}
if (input.httpStatus >= 500) {
return {
kind: 'failure',
reason: STALKER_FAILURE_REASONS.PortalUnavailable,
};
}
if (input.httpStatus !== 200 && input.httpStatus !== 403) {
return { kind: 'none' };
}
const bodyError = extractBodyError(input.value, input.rawBody);
const bodyHasErrorIndicator = hasBodyErrorIndicator(input.value);
if (bodyError === 'Authorization failed') {
return { kind: 'token-rejected' };
}
if (bodyError === 'Access denied') {
@@ -173,18 +192,6 @@ export function classifyStalkerResponseFailure(
) {
return incompatibleResponse();
}
if (input.httpStatus === 429) {
return {
kind: 'failure',
reason: STALKER_FAILURE_REASONS.RateLimited,
};
}
if (input.httpStatus >= 500) {
return {
kind: 'failure',
reason: STALKER_FAILURE_REASONS.PortalUnavailable,
};
}
return { kind: 'none' };
}