# Improve `Retry-After` handling

9 files changed, +1326 −173 in sindresorhus/ky. The author left no usable description, so this brief describes structure only.

| | |
| --- | --- |
| Status | MERGED |
| Source | github:sindresorhus/ky#874 |
| Original | https://github.com/sindresorhus/ky/pull/874 |
| Workspace | Showcase |
| Tags | github, code, typescript, docs |

## What it does

**The change is spread across 9 files in 3 areas, with no single file dominating.**

9 files changed across 3 areas of sindresorhus/ky, 1326 added and 173 removed.

The author left no description on this change, so nothing below comes from their account of it.

**Diagram: Where the change landed. Node size is not to scale; the line counts are exact.**

- ky (9 files, 1499 lines) [accent]
- Tests (2 files, 1044 lines) [good]
- Source (6 files, 437 lines) [accent]
- Docs (1 file, 18 lines) [neutral]
- retry.ts (+603 −80) [neutral]
- ky -> Tests
- ky -> Source
- ky -> Docs
- Tests -> retry.ts : heaviest

- **Heaviest file.** test/retry.ts, +603 −80, which is 46% of the change.
- **Tests moved with it.** 2 test files changed alongside 6 source files.
- **Spread.** 9 files, 1499 changed lines in total.

## How it works

**The largest single edit is in retry.ts.**

Quoted verbatim from the diff. This is the biggest hunk by changed lines, which is where a reviewer's attention usually belongs first.

**Diagram: Source files matched to test files by filename. A name-based match, so treat it as a prompt to look rather than as proof.**

- NO TEST CHANGED (5)
  - Ky.ts (+169 −71) [bad]
  - retry-timing.ts (+173 −0) [bad]
  - options.ts (+6 −4) [bad]
  - HTTPError.ts (+1 −1) [bad]
  - hooks.ts (+1 −1) [bad]
- TEST CHANGED TOO (1)
  - retry.ts (+6 −4) [good]

```typescript
@@ -156,7 +224,306 @@ test('respect Retry-After: 0 and retry immediately', async t => {
 	t.is(requestCount, 5);
 });
 
-test('RateLimit-Reset is treated the same as Retry-After', async t => {
+test.serial('Retry-After number is treated as delay seconds, not timestamp', async t => {
+	const retryServer = await createSingleRetryHeaderServer(t, {
+		'Retry-After': retryAfterTimestampText,
+	});
+
+	await withCapturedTimeouts(async scheduledDelays => {
+		t.is(await ky(retryServer.server.url, {
+			retry: {
+				limit: 1,
+			},
+		}).text(), fixture);
+
+		t.true(scheduledDelays.includes(retryAfterTimestampScheduledDelay));
+	});
+
+	t.is(retryServer.requestCount, 2);
+});
```

_test/retry.ts, +603 −80. The largest hunk in the largest file._

## File map

**Every file this change touches, heaviest first.**

Role is inferred from the path and risk from the path and the line count. Neither was read from the code.

| File | Role | Change | Risk |
| --- | --- | --- | --- |
| `test/retry.ts` | test coverage | modified, patch unavailable (patch truncated at 24000 bytes) | low |
| `test/main.ts` | test coverage | modified, +357 −4 | low |
| `source/core/Ky.ts` | application code | modified, +169 −71 | high |
| `source/core/retry-timing.ts` | application code | added, +173 −0 | medium |
| `readme.md` | documentation | modified, +10 −8 | none |
| `source/types/options.ts` | application code | modified, +6 −4 | low |
| `source/types/retry.ts` | application code | modified, +6 −4 | low |
| `source/errors/HTTPError.ts` | application code | modified, +1 −1 | low |
| `source/types/hooks.ts` | application code | modified, +1 −1 | low |

## Receipts

**Where each number above comes from.**

All of it is arithmetic over the file list and the check results, so it can be recomputed from the source.

- **Claim.** Repeated block: 12 occurrences.
  - Evidence: 
await withCapturedTimeouts(async scheduledDelays => {
t.is(await ky(retryServer.server.url, {
  - Where: test/retry.ts
- **Claim.** 9 files changed, +1326 −173.
  - Evidence: test/retry.ts (+603 −80); test/main.ts (+357 −4); source/core/Ky.ts (+169 −71)
  - Where: https://github.com/sindresorhus/ky/pull/874
- **Claim.** retry.ts carries 46% of the changed lines.
  - Evidence: 683 of 1499 changed lines
  - Where: test/retry.ts
- **Claim.** It arrived as 1 commit.
  - Evidence: Improve `Retry-After` handling
  - Where: commit 6aa7378
- **Claim.** CI reports 0 failing of 6.
  - Evidence: Node.js 22
  - Where: CI check: Node.js 22

## Merge order

**A reading order for the review, not a deployment plan.**

Ordered by how expensive each part is to get wrong, which is a structural property rather than an informed one.

1. **Then retry.ts.** The largest single file in the change, +603 −80.
2. **Finish with the tests.** 2 test files changed. Reading them last tells you what the author believed they were changing.

## What this brief could not check

- No language model read this change. Every statement here is computed from file paths, line counts, and CI status, so it describes the shape of the diff and not what the diff means.
- 1 patch(es) were not retrieved, so any file among them is described by its stat line only.
