Skip to content

Commit 7c5b3e1

Browse files
committed
allow fetch functions to pass headers
1 parent e1d70be commit 7c5b3e1

File tree

1 file changed

+102
-19
lines changed

1 file changed

+102
-19
lines changed

src/lib/mina/fetch.ts

Lines changed: 102 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ export {
5656
getCachedGenesisConstants,
5757
addCachedAccount,
5858
networkConfig,
59+
setMinaDefaultHeaders,
60+
setArchiveDefaultHeaders,
5961
setGraphqlEndpoint,
6062
setGraphqlEndpoints,
6163
setMinaGraphqlFallbackEndpoints,
@@ -85,6 +87,10 @@ type ActionsQueryInputs = {
8587
tokenId?: string;
8688
};
8789

90+
let minaDefaultHeaders: HeadersInit = {};
91+
92+
let archiveDefaultHeaders: HeadersInit = {};
93+
8894
let networkConfig = {
8995
minaEndpoint: '',
9096
minaFallbackEndpoints: [] as string[],
@@ -102,6 +108,52 @@ function checkForValidUrl(url: string) {
102108
}
103109
}
104110

111+
/**
112+
* Internal function to classify the URL as an archive node or not.
113+
* @param url graphql endpoint
114+
* @returns boolean indicating if the URL is an archive node or not
115+
*/
116+
function isArchiveUrl(url: string): boolean {
117+
return (
118+
url === networkConfig.archiveEndpoint ||
119+
networkConfig.archiveFallbackEndpoints.includes(url)
120+
);
121+
}
122+
123+
/**
124+
* Sets up the default headers to be used for all Mina node GraphQL requests, example usage:
125+
* ```typescript
126+
* setMinaDefaultHeaders({ Authorization: 'Bearer example-token' });
127+
* ```
128+
*
129+
* It can be overridden by passing headers to the individual fetch functions, example usage:
130+
* ```typescript
131+
* setMinaDefaultHeaders({ Authorization: 'Bearer default-token' });
132+
* await fetchAccount({publicKey}, minaEndpoint, { headers: { Authorization: 'Bearer override-token' } });
133+
* ```
134+
* @param headers Arbitrary sized headers to be used for all Mina node GraphQL requests.
135+
*/
136+
function setMinaDefaultHeaders(headers: HeadersInit) {
137+
minaDefaultHeaders = headers;
138+
}
139+
140+
/**
141+
* Sets up the default headers to be used for all Archive node GraphQL requests, example usage:
142+
* ```typescript
143+
* setArchiveDefaultHeaders({ Authorization: 'Bearer example-token' });
144+
* ```
145+
*
146+
* It can be overridden by passing headers to the individual fetch functions, example usage:
147+
* ```typescript
148+
* setArchiveDefaultHeaders({ Authorization: 'Bearer default-token' });
149+
* await fetchEvents({publicKey}, archiveEndpoint, { headers: { Authorization: 'Bearer override-token' } });
150+
* ```
151+
* @param headers Arbitrary sized headers to be used for all Mina Archive node GraphQL requests.
152+
*/
153+
function setArchiveDefaultHeaders(headers: HeadersInit) {
154+
archiveDefaultHeaders = headers;
155+
}
156+
105157
function setGraphqlEndpoints([
106158
graphqlEndpoint,
107159
...fallbackEndpoints
@@ -173,13 +225,13 @@ function setLightnetAccountManagerEndpoint(endpoint: string) {
173225
* @param accountInfo.publicKey The specified publicKey to get account information on
174226
* @param accountInfo.tokenId The specified tokenId to get account information on
175227
* @param graphqlEndpoint The graphql endpoint to fetch from
176-
* @param config An object that exposes an additional timeout option
228+
* @param config An object that exposes an additional timeout and header options
177229
* @returns zkapp information on the specified account or an error is thrown
178230
*/
179231
async function fetchAccount(
180232
accountInfo: { publicKey: string | PublicKey; tokenId?: string | Field },
181233
graphqlEndpoint = networkConfig.minaEndpoint,
182-
{ timeout = defaultTimeout } = {}
234+
{ timeout = defaultTimeout, headers }: FetchConfig = {}
183235
): Promise<
184236
| { account: Types.Account; error: undefined }
185237
| { account: undefined; error: FetchError }
@@ -198,6 +250,7 @@ async function fetchAccount(
198250
graphqlEndpoint,
199251
{
200252
timeout,
253+
headers,
201254
}
202255
);
203256
}
@@ -236,7 +289,7 @@ async function fetchAccountInternal(
236289
};
237290
}
238291

239-
type FetchConfig = { timeout?: number };
292+
type FetchConfig = { timeout?: number; headers?: HeadersInit };
240293
type FetchResponse<TDataResponse = any> = { data: TDataResponse; errors?: any };
241294
type FetchError = {
242295
statusCode: number;
@@ -458,11 +511,15 @@ function accountCacheKey(
458511
/**
459512
* Fetches the last block on the Mina network.
460513
*/
461-
async function fetchLastBlock(graphqlEndpoint = networkConfig.minaEndpoint) {
514+
async function fetchLastBlock(
515+
graphqlEndpoint = networkConfig.minaEndpoint,
516+
headers?: HeadersInit
517+
) {
462518
let [resp, error] = await makeGraphqlRequest<LastBlockQueryResponse>(
463519
lastBlockQuery,
464520
graphqlEndpoint,
465-
networkConfig.minaFallbackEndpoints
521+
networkConfig.minaFallbackEndpoints,
522+
{ headers }
466523
);
467524
if (error) throw Error(error.statusText);
468525
let lastBlock = resp?.data?.bestChain?.[0];
@@ -478,11 +535,21 @@ async function fetchLastBlock(graphqlEndpoint = networkConfig.minaEndpoint) {
478535
return network;
479536
}
480537

481-
async function fetchCurrentSlot(graphqlEndpoint = networkConfig.minaEndpoint) {
538+
/**
539+
* Fetches the current slot number of the Mina network.
540+
* @param graphqlEndpoint GraphQL endpoint to fetch from
541+
* @param headers optional headers to pass to the fetch request
542+
* @returns The current slot number
543+
*/
544+
async function fetchCurrentSlot(
545+
graphqlEndpoint = networkConfig.minaEndpoint,
546+
headers?: HeadersInit
547+
) {
482548
let [resp, error] = await makeGraphqlRequest<CurrentSlotResponse>(
483549
currentSlotQuery,
484550
graphqlEndpoint,
485-
networkConfig.minaFallbackEndpoints
551+
networkConfig.minaFallbackEndpoints,
552+
{ headers }
486553
);
487554
if (error) throw Error(`Error making GraphQL request: ${error.statusText}`);
488555
let bestChain = resp?.data?.bestChain;
@@ -597,12 +664,14 @@ function parseEpochData({
597664
*/
598665
async function fetchTransactionStatus(
599666
txId: string,
600-
graphqlEndpoint = networkConfig.minaEndpoint
667+
graphqlEndpoint = networkConfig.minaEndpoint,
668+
headers?: HeadersInit
601669
): Promise<TransactionStatus> {
602670
let [resp, error] = await makeGraphqlRequest<TransactionStatusQueryResponse>(
603671
transactionStatusQuery(txId),
604672
graphqlEndpoint,
605-
networkConfig.minaFallbackEndpoints
673+
networkConfig.minaFallbackEndpoints,
674+
{ headers }
606675
);
607676
if (error) throw Error(error.statusText);
608677
let txStatus = resp?.data?.transactionStatus;
@@ -618,14 +687,15 @@ async function fetchTransactionStatus(
618687
function sendZkapp(
619688
json: string,
620689
graphqlEndpoint = networkConfig.minaEndpoint,
621-
{ timeout = defaultTimeout } = {}
690+
{ timeout = defaultTimeout, headers }: FetchConfig = {}
622691
) {
623692
return makeGraphqlRequest<SendZkAppResponse>(
624693
sendZkappQuery(json),
625694
graphqlEndpoint,
626695
networkConfig.minaFallbackEndpoints,
627696
{
628697
timeout,
698+
headers,
629699
}
630700
);
631701
}
@@ -637,6 +707,7 @@ function sendZkapp(
637707
* @param [accountInfo.tokenId] - The optional token ID for the account.
638708
* @param [graphqlEndpoint=networkConfig.archiveEndpoint] - The GraphQL endpoint to query. Defaults to the Archive Node GraphQL API.
639709
* @param [filterOptions={}] - The optional filter options object.
710+
* @param headers - Optional headers to pass to the fetch request
640711
* @returns A promise that resolves to an array of objects containing event data, block information and transaction information for the account.
641712
* @throws If the GraphQL request fails or the response is invalid.
642713
* @example
@@ -649,7 +720,8 @@ function sendZkapp(
649720
async function fetchEvents(
650721
accountInfo: { publicKey: string; tokenId?: string },
651722
graphqlEndpoint = networkConfig.archiveEndpoint,
652-
filterOptions: EventActionFilterOptions = {}
723+
filterOptions: EventActionFilterOptions = {},
724+
headers?: HeadersInit
653725
) {
654726
if (!graphqlEndpoint)
655727
throw Error(
@@ -663,7 +735,8 @@ async function fetchEvents(
663735
filterOptions
664736
),
665737
graphqlEndpoint,
666-
networkConfig.archiveFallbackEndpoints
738+
networkConfig.archiveFallbackEndpoints,
739+
{ headers }
667740
);
668741
if (error) throw Error(error.statusText);
669742
let fetchedEvents = response?.data.events;
@@ -697,6 +770,7 @@ async function fetchEvents(
697770
*
698771
* @param accountInfo - An {@link ActionsQueryInputs} containing the public key, and optional query parameters for the actions query
699772
* @param graphqlEndpoint - The GraphQL endpoint to fetch from. Defaults to the configured Mina endpoint.
773+
* @param headers - Optional headers to pass to the fetch request
700774
*
701775
* @returns A promise that resolves to an object containing the final actions hash for the account, and a list of actions
702776
* @throws Will throw an error if the GraphQL endpoint is invalid or if the fetch request fails.
@@ -710,7 +784,8 @@ async function fetchEvents(
710784
*/
711785
async function fetchActions(
712786
accountInfo: ActionsQueryInputs,
713-
graphqlEndpoint = networkConfig.archiveEndpoint
787+
graphqlEndpoint = networkConfig.archiveEndpoint,
788+
headers?: HeadersInit
714789
): Promise<
715790
| {
716791
actions: string[][];
@@ -731,7 +806,8 @@ async function fetchActions(
731806
let [response, error] = await makeGraphqlRequest<ActionQueryResponse>(
732807
getActionsQuery(publicKey, actionStates, tokenId),
733808
graphqlEndpoint,
734-
networkConfig.archiveFallbackEndpoints
809+
networkConfig.archiveFallbackEndpoints,
810+
{ headers }
735811
);
736812
// As of 2025-01-07, minascan is running a version of the node which supports `sequenceNumber` and `zkappAccountUpdateIds` fields
737813
// We could consider removing this fallback since no other nodes are widely used
@@ -746,7 +822,8 @@ async function fetchActions(
746822
/* _excludeTransactionInfo= */ true
747823
),
748824
graphqlEndpoint,
749-
networkConfig.archiveFallbackEndpoints
825+
networkConfig.archiveFallbackEndpoints,
826+
{ headers } // Should we pass headers to other nodes?
750827
);
751828
if (error)
752829
throw Error(
@@ -867,12 +944,14 @@ export function createActionsList(
867944
* Fetches genesis constants.
868945
*/
869946
async function fetchGenesisConstants(
870-
graphqlEndpoint = networkConfig.minaEndpoint
947+
graphqlEndpoint = networkConfig.minaEndpoint,
948+
headers?: HeadersInit
871949
): Promise<GenesisConstants> {
872950
let [resp, error] = await makeGraphqlRequest<GenesisConstantsResponse>(
873951
genesisConstantsQuery,
874952
graphqlEndpoint,
875-
networkConfig.minaFallbackEndpoints
953+
networkConfig.minaFallbackEndpoints,
954+
{ headers }
876955
);
877956
if (error) throw Error(error.statusText);
878957
const genesisConstants = resp?.data?.genesisConstants;
@@ -1029,7 +1108,7 @@ async function makeGraphqlRequest<TDataResponse = any>(
10291108
query: string,
10301109
graphqlEndpoint = networkConfig.minaEndpoint,
10311110
fallbackEndpoints: string[],
1032-
{ timeout = defaultTimeout } = {} as FetchConfig
1111+
{ timeout = defaultTimeout, headers } = {} as FetchConfig
10331112
) {
10341113
if (graphqlEndpoint === 'none')
10351114
throw Error(
@@ -1049,7 +1128,11 @@ async function makeGraphqlRequest<TDataResponse = any>(
10491128
try {
10501129
let response = await fetch(url, {
10511130
method: 'POST',
1052-
headers: { 'Content-Type': 'application/json' },
1131+
headers: {
1132+
'Content-Type': 'application/json',
1133+
...(isArchiveUrl(url) ? archiveDefaultHeaders : minaDefaultHeaders),
1134+
...headers,
1135+
},
10531136
body,
10541137
signal: controller.signal,
10551138
});

0 commit comments

Comments
 (0)