-
Notifications
You must be signed in to change notification settings - Fork 38
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
[Bugfix] Implement next.js fetch compatibility #126
Conversation
a1090d0
to
ba9deb7
Compare
@@ -10,7 +10,7 @@ module.exports = { | |||
testPathIgnorePatterns: ['src/integration'], | |||
testTimeout: 100000, | |||
verbose: true, | |||
detectOpenHandles: true, | |||
detectOpenHandles: false, |
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 started getting an error related to TLSWRAP after adding some more integration tests. I should follow up on this later, but for now I don't want to block on it.
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.
According to docs it's a large performance hit and should be generally disabled anyways outside of debugging. Seems fine to me. 👍
// other implementations are stubbed out. | ||
return global.fetch; | ||
} else { | ||
// Use ponyfill as last resort |
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.
// Use ponyfill as last resort | |
// Use polyfill as last resort |
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 is an intentional spelling, actually. cross-fetch can be imported globally ("polyfill") or locally ("ponyfill") according to their readme. Seems smart not to make global changes in a library that could interfere with other stuff in peoples environments.
return global.fetch; | ||
} else { | ||
// Use ponyfill as last resort | ||
return crossFetch; |
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.
So just to confirm my understanding:
- If the user provides fetch, use that
- In Vercel, the global.fetch if statement will be true, so we're good in Vercel land (or do they actually provide
config.fetchApi
?) - When running locally in a Pinecone example app,
cross-fetch
will be used, so that network requests the client needs to initialize will succeed
Do I have that right?
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.
That matches my understanding as well, although I don't think Vercel will be providing anything via config.fetchApi
. Unless of course someone using Vercel opts to provide their own fetch.
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.
My understanding is that next.js loads @vercel/fetch
and it will be available as a global without the need to specifically import it. So the next.js scenario would be the second logical branch here. My testing with the vercel starter showed that this now seems to work as expected.
The ability to pass it through config is just an escape hatch for anyone that has weird/specific needs around the http client configuration that I don't have bandwidth to address at the moment.
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.
Roger, thanks!
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.
@@ -10,7 +10,7 @@ module.exports = { | |||
testPathIgnorePatterns: ['src/integration'], | |||
testTimeout: 100000, | |||
verbose: true, | |||
detectOpenHandles: true, | |||
detectOpenHandles: false, |
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.
According to docs it's a large performance hit and should be generally disabled anyways outside of debugging. Seems fine to me. 👍
return global.fetch; | ||
} else { | ||
// Use ponyfill as last resort | ||
return crossFetch; |
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.
That matches my understanding as well, although I don't think Vercel will be providing anything via config.fetchApi
. Unless of course someone using Vercel opts to provide their own fetch.
@@ -12,7 +8,12 @@ describe('deleteMany', () => { | |||
beforeAll(async () => { | |||
pinecone = new Pinecone(); | |||
|
|||
await createIndexIfDoesNotExist(pinecone, INDEX_NAME); |
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 pulled out since we can use the new suppressConflicts
and just call the create regardless, right?
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.
Yep, sorry I didn't explain that better.
// fetchApi is a complex type that I don't really want to recreate in the | ||
// form of a json schema (seems difficult and error prone). So we will | ||
// rely on TypeScript to guide people in the right direction here. | ||
// But declaring it here as Type.Any() is needed to avoid getting caught | ||
// in the additionalProperties check. | ||
fetchApi: Type.Optional(Type.Any()), |
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.
Makes sense, thanks for the comment.
import crossFetch from 'cross-fetch'; | ||
import type { PineconeConfiguration } from '../data'; | ||
|
||
export const getFetch = (config: PineconeConfiguration) => { |
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.
question: Is it worth adding a tiny unit test file for this utility?
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 is simple enough that I don't think unit-testing would tell us much. I think what would be more valuable here would be to have some next.js-specific integration testing. But I think it's too much additional scope to add as part of this PR. Will have to look into it as a follow-up item.
Problem
Next.js seems to stub out the cross-fetch polyfill which has the effect of silently breaking code which depends on cross-fetch to make API requests.
Related bugs:
Solution
I have added a
getFetch
utility which looks for afetch
implementation already loaded in the global scope and returns the cross-fetch implementation only as a last resort.@vercel/fetch
implementation being used in favor of the disabled polyfill.fetchApi
config option, it will take priority over a fetch in the global scope or the cross-fetch polyfill.Other changes
query
methodencoding
module to resolve a warning message similar to this oneType of Change
Test Plan
I am currently testing this change in the context of work-in-progress to migrate our vercel-starter example to using the v1 version of the client. pinecone-io/pinecone-vercel-starter#14
npm install ../pinecone-ts-client
npm run dev