-
Notifications
You must be signed in to change notification settings - Fork 71
feat!: replace make-fetch-happen with ky and refresh tests/deps #784
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
783b433 to
7e5149b
Compare
Pull Request Test Coverage Report for Build 20067960829Warning: This coverage report may be inaccurate.This pull request's base commit is no longer the HEAD commit of its target branch. This means it includes changes from outside the original pull request, including, potentially, unrelated coverage changes.
Details
💛 - Coveralls |
This reverts commit b5882b0.
- add undici agents/dispatcher bridge so ky honors agent options per call - preserve rejectUnauthorized and proxy support without global env mutation - keep ky throwing on HTTP errors and normalize to Response via helper - remove unused http/https-proxy-agent and update request agent tests to undici
| custom: this.urlHeaders, | ||
| }), | ||
| retry: { | ||
| retries: 2, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
2 is default retry
| etag: undefined, | ||
| contentType: undefined, | ||
| custom: this.headers, | ||
| specVersionSupported: '5.2.0', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was always out of sync so I added client-spec-version.ts helper (please review it)
| appName, | ||
| instanceId, | ||
| connectionId, | ||
| timeout, | ||
| httpOptions, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Turned this into an immutable configuration per client. Maybe we should still enable different timeouts per request, and perhaps some httpOptions, but I also don't think we need them
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 13 out of 15 changed files in this pull request and generated 5 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| connectionId, | ||
| interval, | ||
| etag: undefined, | ||
| contentType: 'application/json', |
Copilot
AI
Dec 5, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider removing the explicit contentType: 'application/json' assignment and instead relying on ky's default behavior for JSON requests. When using the json option in ky, it automatically sets the Content-Type header to application/json, making this explicit assignment redundant.
| contentType: 'application/json', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is fine
| interval, | ||
| etag, | ||
| headers, | ||
| connectionId, |
Copilot
AI
Dec 5, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing contentType parameter in the buildHeaders call. While not required for GET requests, it's inconsistent with the POST request implementation. Consider explicitly passing contentType: undefined for clarity and consistency:
headers: buildHeaders({
appName,
instanceId,
interval,
etag,
headers,
connectionId,
contentType: undefined,
}),| connectionId, | |
| connectionId, | |
| contentType: undefined, |
|
|
||
| export interface HttpOptions { | ||
| agent?: (url: URL) => Agent; | ||
| dispatcher?: (url: URL) => Dispatcher; // this is a breaking change from 'agent'. Ref: https://github.com/Unleash/unleash-node-sdk/pull/332 |
Copilot
AI
Dec 5, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Breaking change documentation: While the inline comment mentions this is a breaking change and references PR #332, consider documenting this breaking change more prominently in the PR description or changelog. The change from agent (which used Node.js http/https Agent) to dispatcher (which uses undici Dispatcher) requires users to update their code.
Additionally, consider adding a deprecation period or providing a migration guide for users who were using the agent option.
| dispatcher?: (url: URL) => Dispatcher; // this is a breaking change from 'agent'. Ref: https://github.com/Unleash/unleash-node-sdk/pull/332 | |
| /** | |
| * @deprecated Use `dispatcher` instead. The `agent` option (Node.js http/https Agent) has been replaced by `dispatcher` (undici Dispatcher). | |
| * See migration guide: https://github.com/Unleash/unleash-node-sdk/pull/332 | |
| */ | |
| agent?: any; | |
| /** | |
| * Custom dispatcher for HTTP requests. | |
| * This replaces the deprecated `agent` option. | |
| * See migration guide: https://github.com/Unleash/unleash-node-sdk/pull/332 | |
| */ | |
| dispatcher?: (url: URL) => Dispatcher; |
| expect(calls).toBe(3); | ||
| if (finished || calls < expectedCalls) return; | ||
| finished = true; | ||
| expect(calls).toBeGreaterThanOrEqual(expectedCalls); |
Copilot
AI
Dec 5, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test assertion uses toBeGreaterThanOrEqual instead of a strict equality check. While this makes the test more resilient, it also makes it less precise. Consider using toBe(expectedCalls) if you want to verify exact retry behavior:
expect(calls).toBe(expectedCalls);This would ensure that retries are working exactly as configured (2 retries + 1 initial = 3 total).
| const getDefaultAgent = (url: URL, rejectUnauthorized?: boolean): Dispatcher => { | ||
| const proxy = getProxyForUrl(url.href); | ||
| const connect = rejectUnauthorized === undefined ? undefined : { rejectUnauthorized }; | ||
|
|
||
| if (!proxy || proxy === '') { | ||
| return new UndiciAgent({ connect }); | ||
| } | ||
|
|
||
| return new ProxyAgent({ uri: proxy, connect }); | ||
| }; | ||
|
|
||
| const createFetchWithDispatcher = | ||
| (httpOptions?: HttpOptions): typeof fetch => | ||
| (input: string | URL | globalThis.Request, init?: RequestInit) => { | ||
| const resolveDispatcher = | ||
| httpOptions?.dispatcher || | ||
| ((targetUrl: URL) => getDefaultAgent(targetUrl, httpOptions?.rejectUnauthorized)); | ||
|
|
||
| const getUrl = (): URL => | ||
| typeof input === 'string' || input instanceof URL ? new URL(input) : new URL(input.url); | ||
|
|
||
| const dispatcher = resolveDispatcher(getUrl()); | ||
|
|
||
| return fetch(input, { | ||
| ...(init ?? {}), | ||
| // @ts-expect-error - dispatcher is not part of RequestInit, but undici accepts it. | ||
| dispatcher, | ||
| }); | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| interface RequestOptions { | ||
| url: string; | ||
| timeout?: number; | ||
| interval?: number; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Something for a future refactor, why would the interval be bound to a request? The only explanation is that we have in on a header, but I resisted from refactoring this part
About the changes