-
Notifications
You must be signed in to change notification settings - Fork 642
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: enhanced provider API /
@tanstack/react-query
peer dependency (…
…#1934) * feat: ensName with enhanced provider and @tanstack/react-query peer dependency fix: append provider api key at build time, skip tests if unavailable chore: align rainbow fetch with other codebases chore: rearrange core utils * chore: changeset * chore: update build.js * chore: tweak enhanced provider hook * chore: add ens localStorage caching * chore: set expiration time to 3 hours for ens name and some few cleanups * chore: describeIf instead of it itif * chore: add describe.skip for now * chore: fix lock file * fix: flexible pnpm patch/minor version * fix: hoist dotenv dev depen to workspace root * chore: tweak changeset * chore: minor bump * fix: align tanstack peer version with wagmi --------- Co-authored-by: Daniel Sinclair <d@niel.nyc>
- Loading branch information
1 parent
f3d10a1
commit 90d6931
Showing
17 changed files
with
8,526 additions
and
6,461 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
--- | ||
"@rainbow-me/rainbowkit": minor | ||
--- | ||
|
||
Introduced the Enhanced Provider to handle fallback resolutions when a Mainnet provider transport is unavailable. | ||
|
||
ENS names for dApps without a Mainnet provider will now properly resolve. Additional conveniences will be soon be rolling out in RainbowKit. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,7 +6,7 @@ on: | |
- main | ||
|
||
env: | ||
pnpm: 9 | ||
pnpm: 9.1.0 | ||
|
||
concurrency: ${{ github.workflow }}-${{ github.ref }} | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
19 changes: 19 additions & 0 deletions
19
packages/rainbowkit/src/core/network/enhancedProvider.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { describe, expect, it } from 'vitest'; | ||
import { enhancedProviderHttp } from './enhancedProvider'; | ||
|
||
describe.skip('createHttpClient', () => { | ||
it("should return 'ok' status for health check endpoint", async () => { | ||
const { data } = await enhancedProviderHttp.get('/healthcheck'); | ||
expect(data).toStrictEqual({ status: 'ok' }); | ||
}); | ||
|
||
it('should throw an error if operation is aborted', async () => { | ||
await expect(() => enhancedProviderHttp.get('/unknown')).rejects.toThrow(); | ||
}); | ||
|
||
it("should throw an error if endpoint doesn't exist", async () => { | ||
await expect(() => enhancedProviderHttp.get('/unknown')).rejects.toThrow( | ||
'Not Found', | ||
); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import { createHttpClient } from './internal/createHttpClient'; | ||
|
||
export const enhancedProviderHttp = createHttpClient({ | ||
baseUrl: 'https://enhanced-provider.rainbow.me', | ||
headers: { | ||
'x-api-key': | ||
process.env.RAINBOW_PROVIDER_API_KEY ?? '__rainbowProviderApiKey', | ||
}, | ||
}); |
12 changes: 12 additions & 0 deletions
12
packages/rainbowkit/src/core/network/internal/createHttpClient.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import { RainbowFetchClient, RainbowFetchRequestOpts } from './rainbowFetch'; | ||
|
||
export function createHttpClient({ | ||
baseUrl, | ||
headers, | ||
params, | ||
timeout, | ||
}: { | ||
baseUrl: string; | ||
} & RainbowFetchRequestOpts) { | ||
return new RainbowFetchClient({ baseUrl, headers, params, timeout }); | ||
} |
200 changes: 200 additions & 0 deletions
200
packages/rainbowkit/src/core/network/internal/rainbowFetch.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,200 @@ | ||
export const RAINBOW_FETCH_ERROR = 'rainbowFetchError'; | ||
|
||
export interface RainbowFetchRequestOpts extends RequestInit { | ||
params?: ConstructorParameters<typeof URLSearchParams>[0]; // type of first argument of URLSearchParams constructor. | ||
timeout?: number; | ||
} | ||
|
||
/** | ||
* rainbowFetch fetches data and handles response edge cases and error handling. | ||
*/ | ||
export async function rainbowFetch<TData>( | ||
url: RequestInfo, | ||
opts: RainbowFetchRequestOpts, | ||
) { | ||
// biome-ignore lint/style/noParameterAssign: ignore | ||
opts = { | ||
headers: {}, | ||
method: 'get', | ||
...opts, // Any other fetch options | ||
timeout: opts.timeout ?? 10_000, // 10 secs | ||
}; | ||
|
||
if (!url) throw new Error('rainbowFetch: Missing url argument'); | ||
|
||
const controller = new AbortController(); | ||
const id = setTimeout(() => controller.abort(), opts.timeout); | ||
|
||
const { body, params, headers, ...otherOpts } = opts; | ||
|
||
const requestBody = | ||
body && typeof body === 'object' ? JSON.stringify(opts.body) : opts.body; | ||
|
||
const response = await fetch(`${url}${createParams(params)}`, { | ||
...otherOpts, | ||
body: requestBody, | ||
headers: { | ||
Accept: 'application/json', | ||
'Content-Type': 'application/json', | ||
...headers, | ||
}, | ||
signal: controller.signal, | ||
}); | ||
|
||
clearTimeout(id); | ||
|
||
const responseBody = (await getBody(response)) as TData; | ||
|
||
if (response.ok) { | ||
const { headers, status } = response; | ||
return { data: responseBody, headers, status }; | ||
} | ||
const errorResponseBody = | ||
typeof responseBody === 'string' ? { error: responseBody } : responseBody; | ||
|
||
const error = generateError({ | ||
requestBody: body, | ||
response, | ||
responseBody: errorResponseBody, | ||
}); | ||
|
||
throw error; | ||
} | ||
|
||
function getBody(response: Response) { | ||
const contentType = response.headers.get('Content-Type'); | ||
if (contentType?.startsWith('application/json')) { | ||
return response.json(); | ||
} | ||
return response.text(); | ||
} | ||
|
||
function createParams(params: RainbowFetchRequestOpts['params']) { | ||
return params && Object.keys(params).length | ||
? `?${new URLSearchParams(params)}` | ||
: ''; | ||
} | ||
|
||
interface RainbowFetchError extends Error { | ||
response?: Response; | ||
responseBody?: any; | ||
requestBody?: RequestInit['body']; | ||
} | ||
|
||
function generateError({ | ||
requestBody, | ||
response, | ||
responseBody, | ||
}: { | ||
requestBody: RequestInit['body']; | ||
response: Response; | ||
responseBody: any; | ||
}) { | ||
const message = | ||
responseBody?.error || | ||
response?.statusText || | ||
'There was an error with the request.'; | ||
|
||
const error: RainbowFetchError = new Error(message); | ||
|
||
error.response = response; | ||
error.responseBody = responseBody; | ||
error.requestBody = requestBody; | ||
|
||
return error; | ||
} | ||
|
||
interface RainbowFetchClientOpts extends RainbowFetchRequestOpts { | ||
baseUrl?: string; | ||
} | ||
|
||
export class RainbowFetchClient { | ||
baseUrl: string; | ||
opts: RainbowFetchRequestOpts; | ||
|
||
constructor(opts: RainbowFetchClientOpts = {}) { | ||
const { baseUrl = '', ...otherOpts } = opts; | ||
this.baseUrl = baseUrl; | ||
this.opts = otherOpts; | ||
} | ||
|
||
/** | ||
* Perform a GET request with the RainbowFetchClient. | ||
*/ | ||
get<TData>(url?: RequestInfo, opts?: RainbowFetchRequestOpts) { | ||
return rainbowFetch<TData>(`${this.baseUrl}${url}`, { | ||
...this.opts, | ||
...(opts || {}), | ||
method: 'get', | ||
}); | ||
} | ||
|
||
/** | ||
* Perform a DELETE request with the RainbowFetchClient. | ||
*/ | ||
delete(url?: RequestInfo, opts?: RainbowFetchRequestOpts) { | ||
return rainbowFetch(`${this.baseUrl}${url}`, { | ||
...this.opts, | ||
...(opts || {}), | ||
method: 'delete', | ||
}); | ||
} | ||
|
||
/** | ||
* Perform a HEAD request with the RainbowFetchClient. | ||
*/ | ||
head(url?: RequestInfo, opts?: RainbowFetchRequestOpts) { | ||
return rainbowFetch(`${this.baseUrl}${url}`, { | ||
...this.opts, | ||
...(opts || {}), | ||
method: 'head', | ||
}); | ||
} | ||
|
||
/** | ||
* Perform a OPTIONS request with the RainbowFetchClient. | ||
*/ | ||
options(url?: RequestInfo, opts?: RainbowFetchRequestOpts) { | ||
return rainbowFetch(`${this.baseUrl}${url}`, { | ||
...this.opts, | ||
...(opts || {}), | ||
method: 'options', | ||
}); | ||
} | ||
|
||
/** | ||
* Perform a POST request with the RainbowFetchClient. | ||
*/ | ||
post<TData>(url?: RequestInfo, body?: any, opts?: RainbowFetchRequestOpts) { | ||
return rainbowFetch<TData>(`${this.baseUrl}${url}`, { | ||
...this.opts, | ||
...(opts || {}), | ||
body, | ||
method: 'post', | ||
}); | ||
} | ||
|
||
/** | ||
* Perform a PUT request with the RainbowFetchClient. | ||
*/ | ||
put<TData>(url?: RequestInfo, body?: any, opts?: RainbowFetchRequestOpts) { | ||
return rainbowFetch<TData>(`${this.baseUrl}${url}`, { | ||
...this.opts, | ||
...(opts || {}), | ||
body, | ||
method: 'put', | ||
}); | ||
} | ||
|
||
/** | ||
* Perform a PATCH request with the RainbowFetchClient. | ||
*/ | ||
patch<TData>(url?: RequestInfo, body?: any, opts?: RainbowFetchRequestOpts) { | ||
return rainbowFetch<TData>(`${this.baseUrl}${url}`, { | ||
...this.opts, | ||
...(opts || {}), | ||
body, | ||
method: 'patch', | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
export function createQueryKey<TArgs>( | ||
/** A categorial key for the query. */ | ||
key: string, | ||
|
||
/** Arguments to pass onto the query function. */ | ||
args: TArgs, | ||
|
||
/** Configuration for the query key. */ | ||
config: { | ||
/** | ||
* A persister version number for the query. | ||
* If a persisterVersion exists, this means that this query | ||
* will be stored in AsyncStorage. | ||
* When a query is stored against a persisterVersion, | ||
* and is later changed, the cache will bust for this query, | ||
* and it will be invalidated. | ||
*/ | ||
persisterVersion?: number; | ||
} = {}, | ||
) { | ||
return [key, args, config] as const; | ||
} |
Oops, something went wrong.