@riverfl0w/dune-client
Version:
A TypeScript client for querying the Dune API, designed to simplify the integration of Dune's powerful analytics into your projects.
330 lines (317 loc) • 11 kB
JavaScript
;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var src_exports = {};
__export(src_exports, {
BaseClient: () => BaseClient,
CancelQueryResponse: () => CancelExecutionResponse_default,
DuneClient: () => DuneClient,
DuneError: () => DuneError,
ErrorResponse: () => ErrorResponse_default,
ExecuteQueryResponse: () => ExecuteQueryResponse_default,
ExecutionClient: () => ExecutionClient,
ExecutionResultResponse: () => ExecutionResultsResponse_default,
ExecutionStatusResponse: () => ExecutionStatusResponse_default,
QueryClient: () => QueryClient,
ResultMetadata: () => ResultMetadata_default
});
module.exports = __toCommonJS(src_exports);
// src/DuneError.ts
var DuneError = class extends Error {
};
// src/schemas/ErrorResponse.ts
var import_zod = require("zod");
var ErrorResponse = import_zod.z.object({
error: import_zod.z.string()
});
var ErrorResponse_default = ErrorResponse;
// src/clients/BaseClient.ts
var MAX_RATE_LIMIT_DELAY = 6e4;
var BaseClient = class {
constructor(apiKey) {
this.apiKey = apiKey;
}
base = "https://api.dune.com/api";
async call({
path,
searchParams,
schema,
delay = 0,
...options
}) {
if (searchParams) {
const search = searchParams.toString();
if (search.length > 0) {
path += `?${search}`;
}
}
const response = await fetch(`${this.base}${path}`, {
...options,
headers: {
...options.headers,
"x-dune-api-key": this.apiKey
}
});
const data = await response.json();
const hasError = await ErrorResponse_default.safeParseAsync(data);
if (hasError.success) {
if (hasError.data.error.match(/too many requests/)) {
await new Promise((resolve) => setTimeout(resolve, delay));
if (delay < MAX_RATE_LIMIT_DELAY) {
const newDelay = (delay + Math.floor(Math.random() * 1e3)) * 2;
return this.call({ path, searchParams, schema, delay: newDelay, ...options });
}
}
throw new DuneError(hasError.data.error);
}
return await schema.parseAsync(data);
}
};
// src/schemas/CancelExecutionResponse.ts
var import_zod2 = require("zod");
var CancelExecutionResponse = import_zod2.z.object({
success: import_zod2.z.boolean()
});
var CancelExecutionResponse_default = CancelExecutionResponse;
// src/schemas/ExecutionResultsResponse.ts
var import_zod4 = require("zod");
// src/schemas/ResultMetadata.ts
var import_zod3 = require("zod");
var ResultMetadata = import_zod3.z.object({
column_names: import_zod3.z.array(import_zod3.z.string()),
result_set_bytes: import_zod3.z.number().int().nonnegative(),
total_row_count: import_zod3.z.number().int().nonnegative(),
datapoint_count: import_zod3.z.number().int().nonnegative(),
pending_time_millis: import_zod3.z.number().int().nonnegative(),
execution_time_millis: import_zod3.z.number().int().nonnegative()
});
var ResultMetadata_default = ResultMetadata;
// src/schemas/ExecutionResultsResponse.ts
var ExecutionResultsResponse = import_zod4.z.object({
execution_id: import_zod4.z.string(),
query_id: import_zod4.z.number(),
is_execution_finished: import_zod4.z.boolean()
}).and(
import_zod4.z.discriminatedUnion("state", [
import_zod4.z.object({
state: import_zod4.z.literal("QUERY_STATE_FAILED"),
submitted_at: import_zod4.z.string().datetime(),
expires_at: import_zod4.z.string().datetime(),
execution_started_at: import_zod4.z.string().datetime(),
execution_ended_at: import_zod4.z.string().datetime(),
error: import_zod4.z.object({
type: import_zod4.z.string(),
message: import_zod4.z.string(),
metadata: import_zod4.z.record(import_zod4.z.unknown())
})
}),
import_zod4.z.object({
state: import_zod4.z.literal("QUERY_STATE_COMPLETED"),
submitted_at: import_zod4.z.string().datetime(),
expires_at: import_zod4.z.string().datetime(),
execution_started_at: import_zod4.z.string().datetime(),
execution_ended_at: import_zod4.z.string().datetime(),
result: import_zod4.z.object({
rows: import_zod4.z.array(import_zod4.z.record(import_zod4.z.unknown())),
metadata: ResultMetadata_default
})
}),
import_zod4.z.object({
state: import_zod4.z.literal("QUERY_STATE_CANCELLED"),
submitted_at: import_zod4.z.string().datetime(),
expires_at: import_zod4.z.string().datetime(),
cancelled_at: import_zod4.z.string().datetime()
}),
import_zod4.z.object({
state: import_zod4.z.literal("QUERY_STATE_EXPIRED")
// TODO: Add more fields
})
])
);
var ExecutionResultsResponse_default = ExecutionResultsResponse;
// src/schemas/ExecutionStatusResponse.ts
var import_zod5 = require("zod");
var ExecutionStatusResponse = import_zod5.z.object({
execution_id: import_zod5.z.string(),
query_id: import_zod5.z.number(),
is_execution_finished: import_zod5.z.boolean()
}).and(
import_zod5.z.discriminatedUnion("state", [
import_zod5.z.object({
state: import_zod5.z.literal("QUERY_STATE_PENDING"),
queue_position: import_zod5.z.number().int().nonnegative().optional(),
submitted_at: import_zod5.z.string().datetime()
}),
import_zod5.z.object({
state: import_zod5.z.literal("QUERY_STATE_EXECUTING"),
submitted_at: import_zod5.z.string().datetime(),
execution_started_at: import_zod5.z.string().datetime()
}),
import_zod5.z.object({
state: import_zod5.z.literal("QUERY_STATE_FAILED"),
submitted_at: import_zod5.z.string().datetime(),
expires_at: import_zod5.z.string().datetime(),
execution_started_at: import_zod5.z.string().datetime(),
execution_ended_at: import_zod5.z.string().datetime()
}),
import_zod5.z.object({
state: import_zod5.z.literal("QUERY_STATE_COMPLETED"),
submitted_at: import_zod5.z.string().datetime(),
expires_at: import_zod5.z.string().datetime(),
execution_started_at: import_zod5.z.string().datetime(),
execution_ended_at: import_zod5.z.string().datetime(),
result_metadata: ResultMetadata_default
}),
import_zod5.z.object({
state: import_zod5.z.literal("QUERY_STATE_CANCELLED"),
submitted_at: import_zod5.z.string().datetime(),
expires_at: import_zod5.z.string().datetime(),
cancelled_at: import_zod5.z.string().datetime()
}),
import_zod5.z.object({
state: import_zod5.z.literal("QUERY_STATE_EXPIRED")
// TODO: Add more fields
})
])
);
var ExecutionStatusResponse_default = ExecutionStatusResponse;
// src/clients/ExecutionClient.ts
var ExecutionClient = class extends BaseClient {
/**
* Get the status of an execution.
* @see https://dune.com/docs/api/api-reference/get-results/execution-status/
*/
status({ execution_id }) {
return this.call({
method: "GET",
path: `/v1/execution/${execution_id}/status`,
schema: ExecutionStatusResponse_default
});
}
/**
* Cancel an execution.
* @see https://dune.com/docs/api/api-reference/execute-queries/cancel-execution/
*/
cancel({ execution_id }) {
return this.call({
method: "POST",
path: `/v1/execution/${execution_id}/cancel`,
schema: CancelExecutionResponse_default
});
}
/**
* Get the results of an execution.
* @see https://dune.com/docs/api/api-reference/get-results/execution-status/
*/
results({ execution_id }) {
return this.call({
method: "GET",
path: `/v1/execution/${execution_id}/results`,
schema: ExecutionResultsResponse_default
});
}
};
// src/schemas/ExecuteQueryResponse.ts
var import_zod6 = require("zod");
var ExecuteQueryResponse = import_zod6.z.object({
execution_id: import_zod6.z.string()
}).and(
import_zod6.z.discriminatedUnion("state", [
import_zod6.z.object({
state: import_zod6.z.literal("QUERY_STATE_PENDING")
}),
import_zod6.z.object({
state: import_zod6.z.literal("QUERY_STATE_EXECUTING")
})
])
);
var ExecuteQueryResponse_default = ExecuteQueryResponse;
// src/clients/QueryClient.ts
var QueryClient = class extends BaseClient {
/**
* Execute am existing Dune query.
* @see https://dune.com/docs/api/api-reference/execute-queries/execute-query-id/
*/
execute({ query_id, ...options }) {
return this.call({
method: "POST",
path: `/v1/query/${query_id}/execute`,
schema: ExecuteQueryResponse_default,
body: JSON.stringify(options)
});
}
/**
* Get the latedst results of a Dune query. This method does NOT execute the query.
* @see https://dune.com/docs/api/api-reference/get-results/latest-results/
*/
results({ query_id, ignore_max_datapoints_per_request }) {
const searchParams = new URLSearchParams();
if (ignore_max_datapoints_per_request) {
searchParams.set("ignore_max_datapoints_per_request", "true");
}
return this.call({
method: "GET",
path: `/v1/query/${query_id}/results`,
searchParams,
schema: ExecutionResultsResponse_default
});
}
};
// src/DuneClient.ts
var DuneClient = class {
execution;
query;
constructor(apiKey) {
this.execution = new ExecutionClient(apiKey);
this.query = new QueryClient(apiKey);
}
/**
* Convenience method to refresh the results of a query.
* It will wait for the query to finish and return the results.
* @param param0
* @returns
*/
async refresh({ cooldown = 500, ...args }) {
const { execution_id } = await this.query.execute(args);
for (; ; ) {
const { state } = await this.execution.status({ execution_id });
if (state === "QUERY_STATE_PENDING" || state === "QUERY_STATE_EXECUTING") {
await new Promise((resolve) => setTimeout(resolve, cooldown));
continue;
}
break;
}
return await this.execution.results({ execution_id });
}
};
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
BaseClient,
CancelQueryResponse,
DuneClient,
DuneError,
ErrorResponse,
ExecuteQueryResponse,
ExecutionClient,
ExecutionResultResponse,
ExecutionStatusResponse,
QueryClient,
ResultMetadata
});
//# sourceMappingURL=index.cjs.map