Skip to content

Commit 0fce61e

Browse files
authored
feat: enable base fetch override (#1279)
1 parent 394d6e3 commit 0fce61e

File tree

7 files changed

+81
-41
lines changed

7 files changed

+81
-41
lines changed

__tests__/rpcChannel.test.ts

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,29 @@
1-
import { LibraryError, RPC07, RpcError } from '../src';
1+
import { LibraryError, RPC06, RPC07, RpcError } from '../src';
22
import { createBlockForDevnet, getTestProvider } from './config/fixtures';
33
import { initializeMatcher } from './config/schema';
44

5-
describe('RPC 0.7.0', () => {
6-
const rpcProvider = getTestProvider(false);
7-
const channel = rpcProvider.channel as RPC07.RpcChannel;
5+
describe('RpcChannel', () => {
6+
const { nodeUrl } = getTestProvider(false).channel;
7+
const channel07 = new RPC07.RpcChannel({ nodeUrl });
88
initializeMatcher(expect);
99

1010
beforeAll(async () => {
1111
await createBlockForDevnet();
1212
});
1313

14-
test('getBlockWithReceipts', async () => {
15-
const response = await channel.getBlockWithReceipts('latest');
16-
expect(response).toMatchSchemaRef('BlockWithTxReceipts');
14+
test('baseFetch override', async () => {
15+
const baseFetch = jest.fn();
16+
const fetchChannel06 = new RPC06.RpcChannel({ nodeUrl, baseFetch });
17+
const fetchChannel07 = new RPC07.RpcChannel({ nodeUrl, baseFetch });
18+
(fetchChannel06.fetch as any)();
19+
expect(baseFetch).toHaveBeenCalledTimes(1);
20+
baseFetch.mockClear();
21+
(fetchChannel07.fetch as any)();
22+
expect(baseFetch).toHaveBeenCalledTimes(1);
1723
});
1824

1925
test('RPC error handling', async () => {
20-
const fetchSpy = jest.spyOn(channel, 'fetch');
26+
const fetchSpy = jest.spyOn(channel07, 'fetch');
2127
fetchSpy.mockResolvedValue({
2228
json: async () => ({
2329
jsonrpc: '2.0',
@@ -32,12 +38,19 @@ describe('RPC 0.7.0', () => {
3238
expect.assertions(3);
3339
try {
3440
// @ts-expect-error
35-
await channel.fetchEndpoint('starknet_chainId');
41+
await channel07.fetchEndpoint('starknet_chainId');
3642
} catch (error) {
3743
expect(error).toBeInstanceOf(LibraryError);
3844
expect(error).toBeInstanceOf(RpcError);
3945
expect((error as RpcError).isType('BLOCK_NOT_FOUND')).toBe(true);
4046
}
4147
fetchSpy.mockRestore();
4248
});
49+
50+
describe('RPC 0.7.0', () => {
51+
test('getBlockWithReceipts', async () => {
52+
const response = await channel07.getBlockWithReceipts('latest');
53+
expect(response).toMatchSchemaRef('BlockWithTxReceipts');
54+
});
55+
});
4356
});

__tests__/rpcProvider.test.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,14 @@ describeIfRpc('RPCProvider', () => {
4747
await createBlockForDevnet();
4848
});
4949

50+
test('baseFetch override', async () => {
51+
const { nodeUrl } = rpcProvider.channel;
52+
const baseFetch = jest.fn();
53+
const fetchProvider = new RpcProvider({ nodeUrl, baseFetch });
54+
(fetchProvider.fetch as any)();
55+
expect(baseFetch.mock.calls.length).toBe(1);
56+
});
57+
5058
test('instantiate from rpcProvider', () => {
5159
const newInsRPCProvider = new RpcProvider();
5260

__tests__/utils/batch.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import fetch from '../../src/utils/fetchPonyfill';
12
import { BatchClient } from '../../src/utils/batch';
23
import { createBlockForDevnet, getTestProvider } from '../config/fixtures';
34
import { initializeMatcher } from '../config/schema';
@@ -9,6 +10,7 @@ describe('Batch Client', () => {
910
nodeUrl: provider.channel.nodeUrl,
1011
headers: provider.channel.headers,
1112
interval: 0,
13+
baseFetch: fetch,
1214
});
1315

1416
initializeMatcher(expect);

src/channel/rpc_0_6.ts

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -42,33 +42,36 @@ export class RpcChannel {
4242

4343
public headers: object;
4444

45-
readonly retries: number;
46-
4745
public requestId: number;
4846

4947
readonly blockIdentifier: BlockIdentifier;
5048

49+
readonly retries: number;
50+
51+
readonly waitMode: boolean; // behave like web2 rpc and return when tx is processed
52+
5153
private chainId?: StarknetChainId;
5254

5355
private specVersion?: string;
5456

5557
private transactionRetryIntervalFallback?: number;
5658

57-
readonly waitMode: Boolean; // behave like web2 rpc and return when tx is processed
58-
5959
private batchClient?: BatchClient;
6060

61+
private baseFetch: NonNullable<RpcProviderOptions['baseFetch']>;
62+
6163
constructor(optionsOrProvider?: RpcProviderOptions) {
6264
const {
63-
nodeUrl,
64-
retries,
65-
headers,
65+
baseFetch,
66+
batch,
6667
blockIdentifier,
6768
chainId,
69+
headers,
70+
nodeUrl,
71+
retries,
6872
specVersion,
69-
waitMode,
7073
transactionRetryIntervalFallback,
71-
batch,
74+
waitMode,
7275
} = optionsOrProvider || {};
7376
if (Object.values(NetworkName).includes(nodeUrl as NetworkName)) {
7477
this.nodeUrl = getDefaultNodeUrl(nodeUrl as NetworkName, optionsOrProvider?.default);
@@ -77,20 +80,23 @@ export class RpcChannel {
7780
} else {
7881
this.nodeUrl = getDefaultNodeUrl(undefined, optionsOrProvider?.default);
7982
}
80-
this.retries = retries || defaultOptions.retries;
81-
this.headers = { ...defaultOptions.headers, ...headers };
82-
this.blockIdentifier = blockIdentifier || defaultOptions.blockIdentifier;
83+
this.baseFetch = baseFetch ?? fetch;
84+
this.blockIdentifier = blockIdentifier ?? defaultOptions.blockIdentifier;
8385
this.chainId = chainId;
86+
this.headers = { ...defaultOptions.headers, ...headers };
87+
this.retries = retries ?? defaultOptions.retries;
8488
this.specVersion = specVersion;
85-
this.waitMode = waitMode || false;
86-
this.requestId = 0;
8789
this.transactionRetryIntervalFallback = transactionRetryIntervalFallback;
90+
this.waitMode = waitMode ?? false;
91+
92+
this.requestId = 0;
8893

8994
if (typeof batch === 'number') {
9095
this.batchClient = new BatchClient({
9196
nodeUrl: this.nodeUrl,
9297
headers: this.headers,
9398
interval: batch,
99+
baseFetch: this.baseFetch,
94100
});
95101
}
96102
}
@@ -110,7 +116,7 @@ export class RpcChannel {
110116
method,
111117
...(params && { params }),
112118
};
113-
return fetch(this.nodeUrl, {
119+
return this.baseFetch(this.nodeUrl, {
114120
method: 'POST',
115121
body: stringify(rpcRequestBody),
116122
headers: this.headers as Record<string, string>,

src/channel/rpc_0_7.ts

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -42,33 +42,36 @@ export class RpcChannel {
4242

4343
public headers: object;
4444

45-
readonly retries: number;
46-
4745
public requestId: number;
4846

4947
readonly blockIdentifier: BlockIdentifier;
5048

49+
readonly retries: number;
50+
51+
readonly waitMode: boolean; // behave like web2 rpc and return when tx is processed
52+
5153
private chainId?: StarknetChainId;
5254

5355
private specVersion?: string;
5456

5557
private transactionRetryIntervalFallback?: number;
5658

57-
readonly waitMode: Boolean; // behave like web2 rpc and return when tx is processed
58-
5959
private batchClient?: BatchClient;
6060

61+
private baseFetch: NonNullable<RpcProviderOptions['baseFetch']>;
62+
6163
constructor(optionsOrProvider?: RpcProviderOptions) {
6264
const {
63-
nodeUrl,
64-
retries,
65-
headers,
65+
baseFetch,
66+
batch,
6667
blockIdentifier,
6768
chainId,
69+
headers,
70+
nodeUrl,
71+
retries,
6872
specVersion,
69-
waitMode,
7073
transactionRetryIntervalFallback,
71-
batch,
74+
waitMode,
7275
} = optionsOrProvider || {};
7376
if (Object.values(NetworkName).includes(nodeUrl as NetworkName)) {
7477
this.nodeUrl = getDefaultNodeUrl(nodeUrl as NetworkName, optionsOrProvider?.default);
@@ -77,20 +80,23 @@ export class RpcChannel {
7780
} else {
7881
this.nodeUrl = getDefaultNodeUrl(undefined, optionsOrProvider?.default);
7982
}
80-
this.retries = retries || defaultOptions.retries;
81-
this.headers = { ...defaultOptions.headers, ...headers };
82-
this.blockIdentifier = blockIdentifier || defaultOptions.blockIdentifier;
83+
this.baseFetch = baseFetch ?? fetch;
84+
this.blockIdentifier = blockIdentifier ?? defaultOptions.blockIdentifier;
8385
this.chainId = chainId;
86+
this.headers = { ...defaultOptions.headers, ...headers };
87+
this.retries = retries ?? defaultOptions.retries;
8488
this.specVersion = specVersion;
85-
this.waitMode = waitMode || false;
86-
this.requestId = 0;
8789
this.transactionRetryIntervalFallback = transactionRetryIntervalFallback;
90+
this.waitMode = waitMode ?? false;
91+
92+
this.requestId = 0;
8893

8994
if (typeof batch === 'number') {
9095
this.batchClient = new BatchClient({
9196
nodeUrl: this.nodeUrl,
9297
headers: this.headers,
9398
interval: batch,
99+
baseFetch: this.baseFetch,
94100
});
95101
}
96102
}
@@ -110,7 +116,7 @@ export class RpcChannel {
110116
method,
111117
...(params && { params }),
112118
};
113-
return fetch(this.nodeUrl, {
119+
return this.baseFetch(this.nodeUrl, {
114120
method: 'POST',
115121
body: stringify(rpcRequestBody),
116122
headers: this.headers as Record<string, string>,

src/types/provider/configuration.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export type RpcProviderOptions = {
1313
specVersion?: string;
1414
default?: boolean;
1515
waitMode?: boolean;
16+
baseFetch?: WindowOrWorkerGlobalScope['fetch'];
1617
feeMarginPercentage?: {
1718
l1BoundMaxAmount: number;
1819
l1BoundMaxPricePerUnit: number;

src/utils/batch/index.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import { stringify } from '../json';
2-
import { RPC } from '../../types';
2+
import { RPC, RpcProviderOptions } from '../../types';
33
import { JRPC } from '../../types/api';
44

55
export type BatchClientOptions = {
66
nodeUrl: string;
77
headers: object;
88
interval: number;
9+
baseFetch: NonNullable<RpcProviderOptions['baseFetch']>;
910
};
1011

1112
export class BatchClient {
@@ -27,10 +28,13 @@ export class BatchClient {
2728

2829
private delayPromiseResolve?: () => void;
2930

31+
private baseFetch: BatchClientOptions['baseFetch'];
32+
3033
constructor(options: BatchClientOptions) {
3134
this.nodeUrl = options.nodeUrl;
3235
this.headers = options.headers;
3336
this.interval = options.interval;
37+
this.baseFetch = options.baseFetch;
3438
}
3539

3640
private async wait(): Promise<void> {
@@ -77,7 +81,7 @@ export class BatchClient {
7781
}
7882

7983
private async sendBatch(requests: JRPC.RequestBody[]) {
80-
const raw = await fetch(this.nodeUrl, {
84+
const raw = await this.baseFetch(this.nodeUrl, {
8185
method: 'POST',
8286
body: stringify(requests),
8387
headers: this.headers as Record<string, string>,

0 commit comments

Comments
 (0)