UNPKG

dune-api-client

Version:

A minimal TypeScript client for interacting with the Dune API.

120 lines (103 loc) 3.54 kB
import { ExecuteQuery, ExecutionStatus, ExecutionResult, CancelQuery, ExecuteQueryOptions, DataOrError, } from './types' export class Dune { private API_KEY: string private BASE_URL = 'https://api.dune.com/api/v1' constructor(API_KEY: string | undefined) { if (!API_KEY) { throw new Error('Dune API key is required') } this.API_KEY = API_KEY } /** * Wrapper to handle HTTP requests with clean typing * @param endpoint API endpoint * @returns Dune response */ private async fetchDune<T>( method: 'GET' | 'POST', endpoint: string, body?: { query_parameters?: ExecuteQueryOptions['params'] } ): Promise<DataOrError<T>> { const res = await fetch(endpoint, { method, headers: { 'x-dune-api-key': this.API_KEY, }, body: method === 'POST' ? JSON.stringify(body) : undefined, }) const json = await res.json() if (json.error) { return json as { error: string } } return { data: json as T } } /** * Execute a query * @param query_id Dune query id * @returns Execution id and state */ async execute( query_id: number, options?: ExecuteQueryOptions ): Promise<DataOrError<ExecuteQuery>> { const endpoint = this.BASE_URL + '/query/' + query_id + '/execute' const body = { query_parameters: options?.params } return await this.fetchDune<ExecuteQuery>('POST', endpoint, body) } /** * Cancel an execution * @param execution_id Dune execution id * @returns Success of cancellation */ async cancel(execution_id: string): Promise<DataOrError<CancelQuery>> { const endpoint = this.BASE_URL + '/execution/' + execution_id + '/cancel' return await this.fetchDune<CancelQuery>('POST', endpoint) } /** * Check the status of an execution * @param execution_id Dune execution id * @returns Status of execution */ async status(execution_id: string): Promise<DataOrError<ExecutionStatus>> { const endpoint = this.BASE_URL + '/execution/' + execution_id + '/status' return await this.fetchDune<ExecutionStatus>('GET', endpoint) } /** * Fetch the results of an execution * @param exec_or_query_id Dune execution id or query id * @returns Results of execution, including row data if available */ async results<T>( exec_or_query_id: string | number, options?: ExecuteQueryOptions ): Promise<DataOrError<ExecutionResult<T>>> { const isIdNumber = /^\d+$/.test(exec_or_query_id.toString()) let endpoint: string if (isIdNumber) { // If `exec_or_query_id` is a number, we want the latest query results // Since this is a GET request, the params need to be in the URL query string // https://dune.com/docs/api/api-reference/get-results/latest-results/ const searchParams = new URLSearchParams() if (options?.params) { for (const [key, value] of Object.entries(options.params)) { const formattedKey = 'params.' + key const formattedValue = value instanceof Date ? value.toISOString() : value.toString() searchParams.append(formattedKey, formattedValue) } } endpoint = `${this.BASE_URL}/query/${exec_or_query_id}/results?${searchParams}` } else { // If `exec_or_query_id` is a string, we want the results of a specific execution endpoint = this.BASE_URL + '/execution/' + exec_or_query_id + '/results' } return await this.fetchDune<ExecutionResult<T>>('GET', endpoint) } }