Skip to content

fix(client): handle HTTP-date format in Retry-After header - #27

Merged
oritwoen merged 4 commits into
mainfrom
fix/retry-after-parsing
Mar 10, 2026
Merged

fix(client): handle HTTP-date format in Retry-After header#27
oritwoen merged 4 commits into
mainfrom
fix/retry-after-parsing

Conversation

@oritwoen

Copy link
Copy Markdown
Member

The Retry-After handler in Client.getJSON runs Number.parseInt on the raw header value. Numeric strings like "120" work fine, but RFC 7231 also allows HTTP-date values ("Wed, 21 Oct 2025 07:28:00 GMT"), and parseInt returns NaN for those. That NaN ends up in RateLimitError.retryAfter, which breaks the error message and any consumer code that reads the field.

Extracted a parseRetryAfter() function that tries numeric first, then Date.parse for HTTP-date, and falls back to 60s when neither works. The registries regxa targets all use numeric values today, but the NaN fallthrough was still a bug waiting to happen.

Addresses item 3 from #18.

parseInt returns NaN for HTTP-date values like
"Wed, 21 Oct 2025 07:28:00 GMT", which propagates into
RateLimitError.retryAfter. Extract parseRetryAfter() that
handles both numeric seconds and HTTP-date, falling back
to 60s for missing or unparseable values.

Ref: #18 (item 3)

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@coderabbitai

coderabbitai Bot commented Mar 10, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 9e7d38d3-ba62-41ca-86d5-ab09a07d9f89

📥 Commits

Reviewing files that changed from the base of the PR and between ba8858f and e8d1c2f.

📒 Files selected for processing (1)
  • test/unit/client.test.ts
📜 Recent review details
🧰 Additional context used
📓 Path-based instructions (2)
test/**/*.test.ts

📄 CodeRabbit inference engine (AGENTS.md)

Use Vitest globals with test/unit and test/e2e split for testing

test/**/*.test.ts: Test files should use *.test.ts naming convention
Vitest globals (describe, it, expect, vi) are enabled and should be used without imports in test files

Files:

  • test/unit/client.test.ts
test/unit/**/*.test.ts

📄 CodeRabbit inference engine (test/AGENTS.md)

Unit tests should rely on mocks/spies rather than external dependencies

Files:

  • test/unit/client.test.ts
🧠 Learnings (12)
📚 Learning: 2026-03-10T07:36:54.862Z
Learnt from: CR
Repo: oritwoen/regxa PR: 0
File: test/AGENTS.md:0-0
Timestamp: 2026-03-10T07:36:54.862Z
Learning: Applies to test/unit/purl.test.ts : PURL contract tests should be located in `test/unit/purl.test.ts` for parse/build validation

Applied to files:

  • test/unit/client.test.ts
📚 Learning: 2026-03-10T07:36:54.862Z
Learnt from: CR
Repo: oritwoen/regxa PR: 0
File: test/AGENTS.md:0-0
Timestamp: 2026-03-10T07:36:54.862Z
Learning: Applies to test/unit/{license,repository}.test.ts : Normalization tests should be located in `test/unit/license.test.ts` and `test/unit/repository.test.ts` for canonical output normalization

Applied to files:

  • test/unit/client.test.ts
📚 Learning: 2026-03-10T07:36:03.586Z
Learnt from: CR
Repo: oritwoen/regxa PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-03-10T07:36:03.586Z
Learning: Applies to src/**/*.ts : Do not duplicate retry/backoff constants outside `src/core/client.ts`; centralize all retry logic

Applied to files:

  • test/unit/client.test.ts
📚 Learning: 2026-03-10T07:36:54.862Z
Learnt from: CR
Repo: oritwoen/regxa PR: 0
File: test/AGENTS.md:0-0
Timestamp: 2026-03-10T07:36:54.862Z
Learning: Applies to test/unit/{lockfile,cached-registry}.test.ts : Cache behavior tests should be located in `test/unit/lockfile.test.ts` and `test/unit/cached-registry.test.ts` for freshness, TTL, integrity, and wrapper behavior validation

Applied to files:

  • test/unit/client.test.ts
📚 Learning: 2026-03-10T07:36:54.862Z
Learnt from: CR
Repo: oritwoen/regxa PR: 0
File: test/AGENTS.md:0-0
Timestamp: 2026-03-10T07:36:54.862Z
Learning: Applies to test/e2e/smoke.test.ts : Live smoke tests should be located in `test/e2e/smoke.test.ts` for network-sensitive ecosystem checks

Applied to files:

  • test/unit/client.test.ts
📚 Learning: 2026-03-10T07:36:03.586Z
Learnt from: CR
Repo: oritwoen/regxa PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-03-10T07:36:03.586Z
Learning: Applies to test/**/*.test.ts : Use Vitest globals with `test/unit` and `test/e2e` split for testing

Applied to files:

  • test/unit/client.test.ts
📚 Learning: 2026-03-10T07:36:54.862Z
Learnt from: CR
Repo: oritwoen/regxa PR: 0
File: test/AGENTS.md:0-0
Timestamp: 2026-03-10T07:36:54.862Z
Learning: Applies to test/unit/errors.test.ts : Error-type expectations tests should be located in `test/unit/errors.test.ts` for custom error classes

Applied to files:

  • test/unit/client.test.ts
📚 Learning: 2026-03-10T07:36:12.605Z
Learnt from: CR
Repo: oritwoen/regxa PR: 0
File: src/AGENTS.md:0-0
Timestamp: 2026-03-10T07:36:12.605Z
Learning: Applies to src/core/client.ts : Implement all fetch and retry behavior only in `src/core/client.ts`

Applied to files:

  • test/unit/client.test.ts
📚 Learning: 2026-03-10T07:36:54.862Z
Learnt from: CR
Repo: oritwoen/regxa PR: 0
File: test/AGENTS.md:0-0
Timestamp: 2026-03-10T07:36:54.862Z
Learning: Applies to test/unit/**/*.test.ts : Unit tests should rely on mocks/spies rather than external dependencies

Applied to files:

  • test/unit/client.test.ts
📚 Learning: 2026-03-10T07:36:12.605Z
Learnt from: CR
Repo: oritwoen/regxa PR: 0
File: src/AGENTS.md:0-0
Timestamp: 2026-03-10T07:36:12.605Z
Learning: Applies to src/**/!(client).ts : Do not implement fetch/retry behavior outside `src/core/client.ts`

Applied to files:

  • test/unit/client.test.ts
📚 Learning: 2026-03-10T07:36:54.862Z
Learnt from: CR
Repo: oritwoen/regxa PR: 0
File: test/AGENTS.md:0-0
Timestamp: 2026-03-10T07:36:54.862Z
Learning: Applies to test/e2e/**/*.test.ts : E2E tests should use real HTTP calls rather than mocks

Applied to files:

  • test/unit/client.test.ts
📚 Learning: 2026-03-10T07:36:54.862Z
Learnt from: CR
Repo: oritwoen/regxa PR: 0
File: test/AGENTS.md:0-0
Timestamp: 2026-03-10T07:36:54.862Z
Learning: Applies to test/**/*.test.ts : Vitest globals (`describe`, `it`, `expect`, `vi`) are enabled and should be used without imports in test files

Applied to files:

  • test/unit/client.test.ts
🧬 Code graph analysis (1)
test/unit/client.test.ts (1)
src/core/client.ts (1)
  • parseRetryAfter (20-34)
🔇 Additional comments (1)
test/unit/client.test.ts (1)

3-62: Coverage matches the parser branches.

This suite hits the real failure paths in parseRetryAfter: nullish/empty fallback, strict numeric parsing, HTTP-date future/past handling, and malformed inputs. The fake-timer case is deterministic and cleans up correctly, so I don't see a test reliability issue here.


📝 Walkthrough

Walkthrough

Added exported helper parseRetryAfter(header) to centralize Retry-After parsing (numeric seconds and HTTP-date). Production 429 handling now calls this helper. Unit tests added covering numeric, date, and malformed inputs; fallback is 60 seconds, past dates yield 0.

Changes

Cohort / File(s) Summary
Retry-After Parser
src/core/client.ts
Added exported `parseRetryAfter(header: string
Parser Tests
test/unit/client.test.ts
New unit tests for parseRetryAfter: numeric values (including zero and large numbers), null/undefined/empty/whitespace → 60, future HTTP-date → computed seconds (uses fake timers), past HTTP-date → 0, and malformed inputs ("120s", "1.5", garbage) → 60.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

A header says "wait" or "now",
parseRetryAfter figures how.
Dates and digits, mess or clear,
Sixty or zero — ready, near. ⏳

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed Title accurately describes the main change: extracting a parseRetryAfter function to handle HTTP-date format in the Retry-After header, fixing the NaN bug.
Description check ✅ Passed Description clearly explains the bug (NaN from parseInt on HTTP-date values), the solution (parseRetryAfter with numeric/date fallback), and the impact on RateLimitError.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/retry-after-parsing
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch fix/retry-after-parsing

Comment @coderabbitai help to get the list of available commands and usage tips.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3fbf7f240e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/core/client.ts Outdated

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 2 files

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.

Requires human review: This change modifies error handling logic in a core path (the HTTP client). Per the instructions, business logic changes in core paths require human review.

Architecture diagram
sequenceDiagram
    participant App as Consumer Application
    participant Client as Client.getJSON()
    participant API as External Registry API
    participant Parser as NEW: parseRetryAfter()

    App->>Client: getJSON(url)
    Client->>API: fetch()

    alt HTTP 200 OK
        API-->>Client: JSON Response
        Client-->>App: Data
    else HTTP 429 Too Many Requests
        API-->>Client: 429 Response + "Retry-After" header
        
        Note over Client,Parser: Extract header value (numeric or date string)
        Client->>Parser: CHANGED: parseRetryAfter(headerValue)
        
        alt Input is Numeric (e.g., "120")
            Parser->>Parser: parseInt(value, 10)
        else NEW: Input is HTTP-date (RFC 7231)
            Parser->>Parser: Date.parse(value)
            Parser->>Parser: Calculate delta: (Target - Date.now())
        else Input Invalid or Empty
            Parser->>Parser: Fallback to 60s
        end
        
        Parser-->>Client: seconds (number)
        
        Note over Client: Instantiate error with parsed seconds
        Client-->>App: throw RateLimitError(retryAfter)
    end

    Note over App,Parser: Ensures RateLimitError.retryAfter is never NaN<ctrl63>
Loading

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/core/client.ts`:
- Around line 23-24: The current parse uses Number.parseInt(header, 10) which
accepts partial strings like "120s"; update the logic so you first validate
header with a full-string digit regexp (e.g. /^\d+$/) before calling
Number.parseInt, and only return the parsed value if the regex matches and the
resulting numeric is >= 0; locate the occurrence of Number.parseInt and the
variables header/numeric in src/core/client.ts and apply this strict-match check
there.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: d3f69bdd-aeee-440c-b941-3eeb60b3ed99

📥 Commits

Reviewing files that changed from the base of the PR and between a61d947 and 3fbf7f2.

📒 Files selected for processing (2)
  • src/core/client.ts
  • test/unit/client.test.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: cubic · AI code reviewer
🧰 Additional context used
📓 Path-based instructions (5)
src/**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.ts: Keep TypeScript imports with .ts extension style in source files
Do not parse PURLs outside src/core/purl.ts; call createFromPURL or parsePURL instead
Do not duplicate retry/backoff constants outside src/core/client.ts; centralize all retry logic
Do not hardcode cache TTL in random modules; use DEFAULT_TTL from src/cache/lockfile.ts
Respect Node.js runtime floor of >=22.6.0 and modern syntax assumptions

Use .ts import suffixes consistently

Files:

  • src/core/client.ts
src/core/client.ts

📄 CodeRabbit inference engine (src/AGENTS.md)

Implement all fetch and retry behavior only in src/core/client.ts

Client owns network behavior defaults (maxRetries, timeout, retry codes)

Files:

  • src/core/client.ts
src/core/**/*.ts

📄 CodeRabbit inference engine (src/core/AGENTS.md)

src/core/**/*.ts: Throw typed errors (InvalidPURLError, NotFoundError, RateLimitError) instead of plain Error in core flows
VersionStatus and Scope are closed unions; keep adapter outputs inside allowed values

Files:

  • src/core/client.ts
test/**/*.test.ts

📄 CodeRabbit inference engine (AGENTS.md)

Use Vitest globals with test/unit and test/e2e split for testing

test/**/*.test.ts: Test files should use *.test.ts naming convention
Vitest globals (describe, it, expect, vi) are enabled and should be used without imports in test files

Files:

  • test/unit/client.test.ts
test/unit/**/*.test.ts

📄 CodeRabbit inference engine (test/AGENTS.md)

Unit tests should rely on mocks/spies rather than external dependencies

Files:

  • test/unit/client.test.ts
🧠 Learnings (7)
📚 Learning: 2026-03-10T07:36:03.586Z
Learnt from: CR
Repo: oritwoen/regxa PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-03-10T07:36:03.586Z
Learning: Applies to src/**/*.ts : Do not duplicate retry/backoff constants outside `src/core/client.ts`; centralize all retry logic

Applied to files:

  • src/core/client.ts
  • test/unit/client.test.ts
📚 Learning: 2026-03-10T07:36:12.605Z
Learnt from: CR
Repo: oritwoen/regxa PR: 0
File: src/AGENTS.md:0-0
Timestamp: 2026-03-10T07:36:12.605Z
Learning: Applies to src/core/client.ts : Implement all fetch and retry behavior only in `src/core/client.ts`

Applied to files:

  • src/core/client.ts
  • test/unit/client.test.ts
📚 Learning: 2026-03-10T07:36:38.679Z
Learnt from: CR
Repo: oritwoen/regxa PR: 0
File: src/core/AGENTS.md:0-0
Timestamp: 2026-03-10T07:36:38.679Z
Learning: Applies to src/core/client.ts : Client owns network behavior defaults (maxRetries, timeout, retry codes)

Applied to files:

  • src/core/client.ts
📚 Learning: 2026-03-10T07:36:12.605Z
Learnt from: CR
Repo: oritwoen/regxa PR: 0
File: src/AGENTS.md:0-0
Timestamp: 2026-03-10T07:36:12.605Z
Learning: Applies to src/**/!(client).ts : Do not implement fetch/retry behavior outside `src/core/client.ts`

Applied to files:

  • src/core/client.ts
📚 Learning: 2026-03-10T07:36:54.862Z
Learnt from: CR
Repo: oritwoen/regxa PR: 0
File: test/AGENTS.md:0-0
Timestamp: 2026-03-10T07:36:54.862Z
Learning: Applies to test/unit/purl.test.ts : PURL contract tests should be located in `test/unit/purl.test.ts` for parse/build validation

Applied to files:

  • test/unit/client.test.ts
📚 Learning: 2026-03-10T07:36:54.862Z
Learnt from: CR
Repo: oritwoen/regxa PR: 0
File: test/AGENTS.md:0-0
Timestamp: 2026-03-10T07:36:54.862Z
Learning: Applies to test/unit/{license,repository}.test.ts : Normalization tests should be located in `test/unit/license.test.ts` and `test/unit/repository.test.ts` for canonical output normalization

Applied to files:

  • test/unit/client.test.ts
📚 Learning: 2026-03-10T07:36:54.862Z
Learnt from: CR
Repo: oritwoen/regxa PR: 0
File: test/AGENTS.md:0-0
Timestamp: 2026-03-10T07:36:54.862Z
Learning: Applies to test/unit/{lockfile,cached-registry}.test.ts : Cache behavior tests should be located in `test/unit/lockfile.test.ts` and `test/unit/cached-registry.test.ts` for freshness, TTL, integrity, and wrapper behavior validation

Applied to files:

  • test/unit/client.test.ts
🧬 Code graph analysis (2)
src/core/client.ts (1)
src/core/errors.ts (1)
  • RateLimitError (51-59)
test/unit/client.test.ts (1)
src/core/client.ts (1)
  • parseRetryAfter (20-33)

Comment thread src/core/client.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@test/unit/client.test.ts`:
- Around line 39-41: Add a unit test that verifies parseRetryAfter correctly
handles numeric strings with leading zeros (e.g., "0120") to document
RFC-compliant behavior; create a new it block (or extend the existing "handles
large numeric values" case) named something like "handles numeric values with
leading zeros" and assert parseRetryAfter("0120") === 120 to ensure leading-zero
inputs are parsed as decimal seconds.
- Around line 24-29: The test "parses HTTP-date in the future" is
timing-dependent and can flake; make it deterministic by either mocking time or
loosening the assertion: use parseRetryAfter with a fixed future timestamp by
stubbing Date.now() (or using vi.useFakeTimers()) so future = new
Date(Date.now() + 90_000) is stable, or change the upper bound assertion on
result produced by parseRetryAfter to a slightly larger value (e.g., allow >0
and <= 95) to tolerate small pauses; update the test referencing parseRetryAfter
and the "parses HTTP-date in the future" spec accordingly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 8c0972db-2a28-47a2-8275-0f9c7a528883

📥 Commits

Reviewing files that changed from the base of the PR and between 3fbf7f2 and c41d2e1.

📒 Files selected for processing (2)
  • src/core/client.ts
  • test/unit/client.test.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (5)
src/**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.ts: Keep TypeScript imports with .ts extension style in source files
Do not parse PURLs outside src/core/purl.ts; call createFromPURL or parsePURL instead
Do not duplicate retry/backoff constants outside src/core/client.ts; centralize all retry logic
Do not hardcode cache TTL in random modules; use DEFAULT_TTL from src/cache/lockfile.ts
Respect Node.js runtime floor of >=22.6.0 and modern syntax assumptions

Use .ts import suffixes consistently

Files:

  • src/core/client.ts
src/core/client.ts

📄 CodeRabbit inference engine (src/AGENTS.md)

Implement all fetch and retry behavior only in src/core/client.ts

Client owns network behavior defaults (maxRetries, timeout, retry codes)

Files:

  • src/core/client.ts
src/core/**/*.ts

📄 CodeRabbit inference engine (src/core/AGENTS.md)

src/core/**/*.ts: Throw typed errors (InvalidPURLError, NotFoundError, RateLimitError) instead of plain Error in core flows
VersionStatus and Scope are closed unions; keep adapter outputs inside allowed values

Files:

  • src/core/client.ts
test/**/*.test.ts

📄 CodeRabbit inference engine (AGENTS.md)

Use Vitest globals with test/unit and test/e2e split for testing

test/**/*.test.ts: Test files should use *.test.ts naming convention
Vitest globals (describe, it, expect, vi) are enabled and should be used without imports in test files

Files:

  • test/unit/client.test.ts
test/unit/**/*.test.ts

📄 CodeRabbit inference engine (test/AGENTS.md)

Unit tests should rely on mocks/spies rather than external dependencies

Files:

  • test/unit/client.test.ts
🧠 Learnings (7)
📚 Learning: 2026-03-10T07:36:03.586Z
Learnt from: CR
Repo: oritwoen/regxa PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-03-10T07:36:03.586Z
Learning: Applies to src/**/*.ts : Do not duplicate retry/backoff constants outside `src/core/client.ts`; centralize all retry logic

Applied to files:

  • src/core/client.ts
  • test/unit/client.test.ts
📚 Learning: 2026-03-10T07:36:12.605Z
Learnt from: CR
Repo: oritwoen/regxa PR: 0
File: src/AGENTS.md:0-0
Timestamp: 2026-03-10T07:36:12.605Z
Learning: Applies to src/core/client.ts : Implement all fetch and retry behavior only in `src/core/client.ts`

Applied to files:

  • src/core/client.ts
  • test/unit/client.test.ts
📚 Learning: 2026-03-10T07:36:38.679Z
Learnt from: CR
Repo: oritwoen/regxa PR: 0
File: src/core/AGENTS.md:0-0
Timestamp: 2026-03-10T07:36:38.679Z
Learning: Applies to src/core/client.ts : Client owns network behavior defaults (maxRetries, timeout, retry codes)

Applied to files:

  • src/core/client.ts
📚 Learning: 2026-03-10T07:36:12.605Z
Learnt from: CR
Repo: oritwoen/regxa PR: 0
File: src/AGENTS.md:0-0
Timestamp: 2026-03-10T07:36:12.605Z
Learning: Applies to src/**/!(client).ts : Do not implement fetch/retry behavior outside `src/core/client.ts`

Applied to files:

  • src/core/client.ts
📚 Learning: 2026-03-10T07:36:54.862Z
Learnt from: CR
Repo: oritwoen/regxa PR: 0
File: test/AGENTS.md:0-0
Timestamp: 2026-03-10T07:36:54.862Z
Learning: Applies to test/unit/purl.test.ts : PURL contract tests should be located in `test/unit/purl.test.ts` for parse/build validation

Applied to files:

  • test/unit/client.test.ts
📚 Learning: 2026-03-10T07:36:54.862Z
Learnt from: CR
Repo: oritwoen/regxa PR: 0
File: test/AGENTS.md:0-0
Timestamp: 2026-03-10T07:36:54.862Z
Learning: Applies to test/unit/{license,repository}.test.ts : Normalization tests should be located in `test/unit/license.test.ts` and `test/unit/repository.test.ts` for canonical output normalization

Applied to files:

  • test/unit/client.test.ts
📚 Learning: 2026-03-10T07:36:54.862Z
Learnt from: CR
Repo: oritwoen/regxa PR: 0
File: test/AGENTS.md:0-0
Timestamp: 2026-03-10T07:36:54.862Z
Learning: Applies to test/unit/{lockfile,cached-registry}.test.ts : Cache behavior tests should be located in `test/unit/lockfile.test.ts` and `test/unit/cached-registry.test.ts` for freshness, TTL, integrity, and wrapper behavior validation

Applied to files:

  • test/unit/client.test.ts
🧬 Code graph analysis (2)
src/core/client.ts (1)
src/core/errors.ts (1)
  • RateLimitError (51-59)
test/unit/client.test.ts (1)
src/core/client.ts (1)
  • parseRetryAfter (20-34)
🔇 Additional comments (3)
src/core/client.ts (2)

20-34: Solid implementation addressing the RFC 7231 edge cases.

The strict /^\d+$/ check properly rejects partial numerics like "120s" and decimals like "1.5" that parseInt would have accepted. The letter-check guard before Date.parse is a nice optimization to skip date parsing for purely numeric-like garbage.

One small note: Math.max(seconds, 0) returns 0 for past dates, which matches test expectations but differs from the function's documented "60 when unparseable" behavior. Past dates are technically parseable, just not useful. The current behavior (returning 0) is probably more correct since the server meant "retry now" - just flagging the doc mismatch.


84-84: Clean integration with RateLimitError.

Delegates parsing to the new utility. Looking at RateLimitError in src/core/errors.ts, it expects a number and builds the message from it - this works correctly now that parseRetryAfter always returns a valid number (no more NaN propagation).

test/unit/client.test.ts (1)

1-54: Good coverage of the main parsing scenarios.

Tests hit all the important cases from the PR description: numeric, HTTP-date, garbage, and the previously-broken partial numeric inputs.

Comment thread test/unit/client.test.ts
Comment thread test/unit/client.test.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@test/unit/client.test.ts`:
- Around line 24-29: The test "parses HTTP-date in the future" uses
vi.useFakeTimers() and vi.setSystemTime(...) but calls vi.useRealTimers()
unconditionally at the end; wrap the fake-timer setup and assertions in a
try/finally so vi.useRealTimers() always runs even if parseRetryAfter(...) or
expect(...) throws. Locate the test block that calls vi.useFakeTimers(),
vi.setSystemTime(new Date(...)), parseRetryAfter(...), and vi.useRealTimers()
and move the assertion into the try with vi.useRealTimers() in the finally to
guarantee cleanup.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 871c85d0-7007-42e5-9e10-fc51fbd697e3

📥 Commits

Reviewing files that changed from the base of the PR and between c41d2e1 and ba8858f.

📒 Files selected for processing (1)
  • test/unit/client.test.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (2)
test/**/*.test.ts

📄 CodeRabbit inference engine (AGENTS.md)

Use Vitest globals with test/unit and test/e2e split for testing

test/**/*.test.ts: Test files should use *.test.ts naming convention
Vitest globals (describe, it, expect, vi) are enabled and should be used without imports in test files

Files:

  • test/unit/client.test.ts
test/unit/**/*.test.ts

📄 CodeRabbit inference engine (test/AGENTS.md)

Unit tests should rely on mocks/spies rather than external dependencies

Files:

  • test/unit/client.test.ts
🧠 Learnings (6)
📚 Learning: 2026-03-10T07:36:54.862Z
Learnt from: CR
Repo: oritwoen/regxa PR: 0
File: test/AGENTS.md:0-0
Timestamp: 2026-03-10T07:36:54.862Z
Learning: Applies to test/unit/purl.test.ts : PURL contract tests should be located in `test/unit/purl.test.ts` for parse/build validation

Applied to files:

  • test/unit/client.test.ts
📚 Learning: 2026-03-10T07:36:03.586Z
Learnt from: CR
Repo: oritwoen/regxa PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-03-10T07:36:03.586Z
Learning: Applies to src/**/*.ts : Do not duplicate retry/backoff constants outside `src/core/client.ts`; centralize all retry logic

Applied to files:

  • test/unit/client.test.ts
📚 Learning: 2026-03-10T07:36:54.862Z
Learnt from: CR
Repo: oritwoen/regxa PR: 0
File: test/AGENTS.md:0-0
Timestamp: 2026-03-10T07:36:54.862Z
Learning: Applies to test/unit/{license,repository}.test.ts : Normalization tests should be located in `test/unit/license.test.ts` and `test/unit/repository.test.ts` for canonical output normalization

Applied to files:

  • test/unit/client.test.ts
📚 Learning: 2026-03-10T07:36:12.605Z
Learnt from: CR
Repo: oritwoen/regxa PR: 0
File: src/AGENTS.md:0-0
Timestamp: 2026-03-10T07:36:12.605Z
Learning: Applies to src/core/client.ts : Implement all fetch and retry behavior only in `src/core/client.ts`

Applied to files:

  • test/unit/client.test.ts
📚 Learning: 2026-03-10T07:36:54.862Z
Learnt from: CR
Repo: oritwoen/regxa PR: 0
File: test/AGENTS.md:0-0
Timestamp: 2026-03-10T07:36:54.862Z
Learning: Applies to test/unit/{lockfile,cached-registry}.test.ts : Cache behavior tests should be located in `test/unit/lockfile.test.ts` and `test/unit/cached-registry.test.ts` for freshness, TTL, integrity, and wrapper behavior validation

Applied to files:

  • test/unit/client.test.ts
📚 Learning: 2026-03-10T07:36:54.862Z
Learnt from: CR
Repo: oritwoen/regxa PR: 0
File: test/AGENTS.md:0-0
Timestamp: 2026-03-10T07:36:54.862Z
Learning: Applies to test/e2e/smoke.test.ts : Live smoke tests should be located in `test/e2e/smoke.test.ts` for network-sensitive ecosystem checks

Applied to files:

  • test/unit/client.test.ts
🧬 Code graph analysis (1)
test/unit/client.test.ts (1)
src/core/client.ts (1)
  • parseRetryAfter (20-34)
🔇 Additional comments (2)
test/unit/client.test.ts (2)

3-23: Good coverage of the numeric and default branches.

These cases pin down the direct numeric path and the 60-second fallback, so this helper cannot silently drift back to NaN for nullish or empty inputs.


32-59: The edge-case matrix here is worth keeping.

Past-date clamping, strict rejection of "120s" and "1.5", and the leading-zero case all document behavior that callers will otherwise have to guess from the implementation.

Comment thread test/unit/client.test.ts Outdated
@oritwoen oritwoen self-assigned this Mar 10, 2026
@oritwoen
oritwoen merged commit 731c826 into main Mar 10, 2026
3 checks passed
@oritwoen
oritwoen deleted the fix/retry-after-parsing branch March 10, 2026 12:10
@oritwoen
oritwoen restored the fix/retry-after-parsing branch August 13, 2026 10:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants