UNPKG

@messari/sdk

Version:

Messari SDK provides a type-safe, intuitive interface for accessing Messari's suite of crypto data and AI APIs.

1,022 lines 45.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.MessariClient = void 0; const types_1 = require("../types"); const utils_1 = require("../utils"); const logging_1 = require("../logging"); const error_1 = require("../error"); const base_1 = require("./base"); /** * MessariClient is the main client class for interacting with the Messari API. * It provides a comprehensive interface for accessing market data, news, intelligence, * and AI-powered features through typed methods and robust error handling. * * Key features: * - Full TypeScript support with strongly typed requests and responses * - Configurable logging and error handling * - Built-in request timeout and retry logic * - Pagination helpers for listing endpoints * - Event system for monitoring requests, responses and errors * - Connection pooling support via HTTP agent * - Custom fetch implementation support */ class MessariClient extends base_1.MessariClientBase { constructor(options) { super(); this.ai = { createChatCompletion: (params, options) => this.request({ method: types_1.createChatCompletionOpenAI.method, path: types_1.createChatCompletionOpenAI.path(), body: (0, utils_1.pick)(params, types_1.createChatCompletionOpenAI.bodyParams), options, }), createChatCompletionStream: (params, options) => this.requestStream({ method: types_1.createChatCompletionOpenAI.method, path: types_1.createChatCompletionOpenAI.path(), body: { ...(0, utils_1.pick)(params, types_1.createChatCompletionOpenAI.bodyParams), stream: true }, options, }), extractEntities: (params, options) => this.request({ method: types_1.extractEntities.method, path: types_1.extractEntities.path(), body: (0, utils_1.pick)(params, types_1.extractEntities.bodyParams), options, }), }; /** * @deprecated Asset is Work-in-Progress and not production ready */ this.asset = { getAssetsV2: async (params = {}, options) => { return this.requestWithMetadata({ method: types_1.getAssetsV2.method, path: types_1.getAssetsV2.path(), queryParams: (0, utils_1.pick)(params, types_1.getAssetsV2.queryParams), options, }); }, getAssetDetails: async (params, options) => { return this.requestWithMetadata({ method: types_1.getAssetDetails.method, path: types_1.getAssetDetails.path(), queryParams: (0, utils_1.pick)(params, types_1.getAssetDetails.queryParams), options, }); }, getAssetsTimeseriesCatalog: async (options) => { return this.requestWithMetadata({ method: types_1.getAssetsTimeseriesCatalog.method, path: types_1.getAssetsTimeseriesCatalog.path(), options, }); }, getAssetsV2ATH: async (params = {}, options) => { return this.requestWithMetadata({ method: types_1.getAssetsV2ATH.method, path: types_1.getAssetsV2ATH.path(), queryParams: (0, utils_1.pick)(params, types_1.getAssetsV2ATH.queryParams), options, }); }, getAssetsV2ROI: async (params = {}, options) => { return this.requestWithMetadata({ method: types_1.getAssetsV2ROI.method, path: types_1.getAssetsV2ROI.path(), queryParams: (0, utils_1.pick)(params, types_1.getAssetsV2ROI.queryParams), options, }); }, getAssetTimeseries: async (params, options) => { return this.requestWithMetadata({ method: types_1.getAssetTimeseries.method, path: types_1.getAssetTimeseries.path(params), queryParams: (0, utils_1.pick)(params, types_1.getAssetTimeseries.queryParams), options, }); }, getAssetTimeseriesWithGranularity: async (params, options) => { return this.requestWithMetadata({ method: types_1.getAssetTimeseriesWithGranularity.method, path: types_1.getAssetTimeseriesWithGranularity.path(params), queryParams: (0, utils_1.pick)(params, types_1.getAssetTimeseriesWithGranularity.queryParams), options, }); }, }; /** * @deprecated Exchanges is Work-in-Progress and not production ready */ this.exchanges = { getExchanges: async (params = {}, options) => { return this.requestWithMetadata({ method: types_1.getExchanges.method, path: types_1.getExchanges.path(), queryParams: (0, utils_1.pick)(params, types_1.getExchanges.queryParams), options, }); }, getExchangeById: async (params, options) => { return this.requestWithMetadata({ method: types_1.getExchange.method, path: types_1.getExchange.path(params), options, }); }, getExchangeMetrics: async (options) => { return this.requestWithMetadata({ method: types_1.getExchangeMetrics.method, path: types_1.getExchangeMetrics.path(), options, }); }, getExchangeTimeseries: async (params, options) => { return this.requestWithMetadata({ method: types_1.getExchangeTimeseries.method, path: types_1.getExchangeTimeseries.path(params), queryParams: (0, utils_1.pick)(params, types_1.getExchangeTimeseries.queryParams), options, }); }, }; this.networks = { getNetworks: async (params = {}, options) => { return this.requestWithMetadata({ method: types_1.getNetworks.method, path: types_1.getNetworks.path(), queryParams: (0, utils_1.pick)(params, types_1.getNetworks.queryParams), options, }); }, getNetworkById: async (params, options) => { return this.requestWithMetadata({ method: types_1.getNetwork.method, path: types_1.getNetwork.path(params), options, }); }, getNetworkMetrics: async (options) => { return this.requestWithMetadata({ method: types_1.getNetworkMetrics.method, path: types_1.getNetworkMetrics.path(), options, }); }, getNetworkTimeseries: async (params, options) => { return this.requestWithMetadata({ method: types_1.getNetworkTimeseries.method, path: types_1.getNetworkTimeseries.path(params), queryParams: (0, utils_1.pick)(params, types_1.getNetworkTimeseries.queryParams), options, }); }, }; /** * @deprecated Markets is Work-in-Progress and not production ready */ this.markets = { getMarkets: async (params = {}, options) => { return this.requestWithMetadata({ method: types_1.getMarkets.method, path: types_1.getMarkets.path(), queryParams: (0, utils_1.pick)(params, types_1.getMarkets.queryParams), options, }); }, getMarketById: async (params, options) => { return this.requestWithMetadata({ method: types_1.getMarket.method, path: types_1.getMarket.path(params), options, }); }, getMarketMetrics: async (options) => { return this.requestWithMetadata({ method: types_1.getMarketMetrics.method, path: types_1.getMarketMetrics.path(), options, }); }, getMarketTimeseries: async (params, options) => { return this.requestWithMetadata({ method: types_1.getMarketTimeseries.method, path: types_1.getMarketTimeseries.path(params), queryParams: (0, utils_1.pick)(params, types_1.getMarketTimeseries.queryParams), options, }); }, }; /** * @deprecated Intel is Work-in-Progress and not production ready */ this.intel = { getAllEvents: async (params = {}, options) => { const fetchPage = async (p, o) => { return this.requestWithMetadata({ method: types_1.getAllEvents.method, path: types_1.getAllEvents.path(), body: (0, utils_1.pick)(p, types_1.getAllEvents.bodyParams), options: o, }); }; const response = await fetchPage(params, options); return this.paginate(params, fetchPage, response, options); }, getById: async (params, options) => { return this.request({ method: types_1.getEventAndHistory.method, path: types_1.getEventAndHistory.path(params), options, }); }, getAllAssets: async (params = {}, options) => { const fetchPage = async (p, o) => { return this.requestWithMetadata({ method: types_1.getAllAssets.method, path: types_1.getAllAssets.path(), queryParams: (0, utils_1.pick)(p, types_1.getAllAssets.queryParams), options: o, }); }; const response = await fetchPage(params, options); return this.paginate(params, fetchPage, response, options); }, }; /** * @deprecated Fundraising is Work-in-Progress and not production ready */ this.fundraising = { getFundingRounds: async (params) => { return this.requestWithMetadata({ method: types_1.getFundingRounds.method, path: types_1.getFundingRounds.path(), queryParams: (0, utils_1.pick)(params, types_1.getFundingRounds.queryParams), }); }, getFundingRoundsInvestors: async (params) => { return this.requestWithMetadata({ method: types_1.getFundingRoundsInvestors.method, path: types_1.getFundingRoundsInvestors.path(), queryParams: (0, utils_1.pick)(params, types_1.getFundingRoundsInvestors.queryParams), }); }, getAcquisitionDeals: async (params) => { return this.requestWithMetadata({ method: types_1.getAcquisitionDeals.method, path: types_1.getAcquisitionDeals.path(), queryParams: (0, utils_1.pick)(params, types_1.getAcquisitionDeals.queryParams), }); }, getOrganizations: async (params) => { return this.requestWithMetadata({ method: types_1.getOrganizations.method, path: types_1.getOrganizations.path(), queryParams: (0, utils_1.pick)(params, types_1.getOrganizations.queryParams), }); }, getProjects: async (params) => { return this.requestWithMetadata({ method: types_1.getProjects.method, path: types_1.getProjects.path(), queryParams: (0, utils_1.pick)(params, types_1.getProjects.queryParams), }); }, }; /** * @deprecated TokenUnlocks is Work-in-Progress and not production ready */ this.tokenUnlocks = { getSupportedAssets: async (params = {}, options) => { return this.request({ method: types_1.getTokenUnlockSupportedAssets.method, path: types_1.getTokenUnlockSupportedAssets.path(), queryParams: (0, utils_1.pick)(params, types_1.getTokenUnlockSupportedAssets.queryParams), options, }); }, getAllocations: async (params = {}, options) => { return this.request({ method: types_1.getTokenUnlockAllocations.method, path: types_1.getTokenUnlockAllocations.path(), queryParams: (0, utils_1.pick)(params, types_1.getTokenUnlockAllocations.queryParams), options, }); }, getVestingSchedule: async (params, options) => { return this.request({ method: types_1.getTokenUnlockVestingSchedule.method, path: types_1.getTokenUnlockVestingSchedule.path(params), queryParams: (0, utils_1.pick)(params, types_1.getTokenUnlockVestingSchedule.queryParams), options, }); }, getUnlocks: async (params, options) => { return this.request({ method: types_1.getTokenUnlocks.method, path: types_1.getTokenUnlocks.path(params), queryParams: (0, utils_1.pick)(params, types_1.getTokenUnlocks.queryParams), options, }); }, getEvents: async (params, options) => { return this.request({ method: types_1.getTokenUnlockEvents.method, path: types_1.getTokenUnlockEvents.path(params), queryParams: (0, utils_1.pick)(params, types_1.getTokenUnlockEvents.queryParams), options, }); }, }; /** * @deprecated News is Work-in-Progress and not production ready */ this.news = { getNewsFeedPaginated: async (params, options) => { const fetchPage = async (p, o) => { return this.requestWithMetadata({ method: types_1.getNewsFeed.method, path: types_1.getNewsFeed.path(), queryParams: (0, utils_1.pick)(p, types_1.getNewsFeed.queryParams), options: o, }); }; const initialResponse = await fetchPage(params, options); return this.paginate(params, fetchPage, initialResponse, options); }, getNewsFeedAssetsPaginated: async (params, options) => { const fetchPage = async (p, o) => { return this.requestWithMetadata({ method: types_1.getNewsFeedAssets.method, path: types_1.getNewsFeedAssets.path(), queryParams: (0, utils_1.pick)(p, types_1.getNewsFeedAssets.queryParams), options: o, }); }; const initialResponse = await fetchPage(params, options); return this.paginate(params, fetchPage, initialResponse, options); }, getNewsSourcesPaginated: async (params, options) => { const fetchPage = async (p, o) => { return this.requestWithMetadata({ method: types_1.getNewsSources.method, path: types_1.getNewsSources.path(), queryParams: (0, utils_1.pick)(p, types_1.getNewsSources.queryParams), options: o, }); }; const initialResponse = await fetchPage(params, options); return this.paginate(params, fetchPage, initialResponse, options); }, }; /** * @deprecated Research is Work-in-Progress and not production ready */ this.research = { getResearchReports: (params, options) => this.request({ method: types_1.getResearchReports.method, path: types_1.getResearchReports.path(), queryParams: (0, utils_1.pick)(params, types_1.getResearchReports.queryParams), options, }), getResearchReportById: (params, options) => this.request({ method: types_1.getResearchReportById.method, path: types_1.getResearchReportById.path(params), options, }), getResearchReportTags: (options) => this.request({ method: types_1.getResearchReportTags.method, path: types_1.getResearchReportTags.path(), options, }), }; /** * @deprecated Diligence is Work-in-Progress and not production ready */ this.diligence = { getDiligencePreview: async () => { return this.request({ method: types_1.getPreviews.method, path: types_1.getPreviews.path(), }); }, getDiligenceReport: async (params) => { return this.request({ method: types_1.getReportByAssetID.method, path: types_1.getReportByAssetID.path(params), }); }, }; /** * User Management API service * Provides methods for managing user-specific data like watchlists, credits, and permissions */ this.userManagement = { getTeamAllowance: (options) => this.request({ method: types_1.getTeamAllowance.method, path: types_1.getTeamAllowance.path(), options, }), getPermissions: (options) => this.request({ method: types_1.getPermissions.method, path: types_1.getPermissions.path(), options, }), listWatchlists: (options) => this.request({ method: types_1.listWatchlists.method, path: types_1.listWatchlists.path(), options, }), createWatchlist: (params, options) => this.request({ method: types_1.createWatchlist.method, path: types_1.createWatchlist.path(), body: (0, utils_1.pick)(params, types_1.createWatchlist.bodyParams), options, }), getWatchlist: (params, options) => this.request({ method: types_1.getWatchlist.method, path: types_1.getWatchlist.path(params), options, }), updateWatchlist: (params, options) => this.request({ method: types_1.updateWatchlist.method, path: types_1.updateWatchlist.path({ id: params.id }), body: (0, utils_1.pick)(params, types_1.updateWatchlist.bodyParams), options, }), deleteWatchlist: (params, options) => this.request({ method: types_1.deleteWatchlist.method, path: types_1.deleteWatchlist.path(params), options, }), modifyWatchlistAssets: (params, options) => this.request({ method: types_1.modifyWatchlistAssets.method, path: types_1.modifyWatchlistAssets.path({ id: params.id }), body: (0, utils_1.pick)(params, types_1.modifyWatchlistAssets.bodyParams), options, }), }; this.apiKey = options.apiKey; this.baseUrl = options.baseUrl || "https://api.messari.io"; this.timeoutMs = options.timeoutMs || 60000; // 60 seconds this.fetchFn = options.fetch || fetch; this.agent = options.agent; // Handle logger initialization with disableLogging option this.isLoggingDisabled = !!options.disableLogging; if (this.isLoggingDisabled) { this.logger = logging_1.noOpLogger; } else { const baseLogger = options.logger || (0, logging_1.makeConsoleLogger)("messari-client"); this.logger = (0, logging_1.createFilteredLogger)(baseLogger, options.logLevel ?? logging_1.LogLevel.INFO); } this.defaultHeaders = { "Content-Type": "application/json", "x-messari-api-key": this.apiKey, ...options.defaultHeaders, }; // Initialize event handlers this.eventHandlers = new Map(); // Register event handlers from options if (options.onError) { this.on("error", options.onError); } if (options.onRequest) { this.on("request", options.onRequest); } if (options.onResponse) { this.on("response", options.onResponse); } } async request({ method, path, body, queryParams = {}, options = {} }) { this.logger(logging_1.LogLevel.DEBUG, "request start", { method, url: `${this.baseUrl}${path}`, queryParams, }); this.emit("request", { method, path, queryParams, }); const queryString = Object.entries(queryParams) .filter(([_, value]) => value !== undefined) .map(([key, value]) => { if (Array.isArray(value)) { return value.map((item) => `${encodeURIComponent(key)}=${encodeURIComponent(String(item))}`).join("&"); } return `${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`; }) .join("&"); const url = `${this.baseUrl}${path}${queryString ? `?${queryString}` : ""}`; const headers = { ...this.defaultHeaders, ...options.headers, }; const timeoutMs = options.timeoutMs || this.timeoutMs; try { const response = await error_1.RequestTimeoutError.rejectAfterTimeout(this.fetchFn(url, { method, headers, body: body ? JSON.stringify(body) : undefined, signal: options.signal, cache: options.cache, credentials: options.credentials, integrity: options.integrity, keepalive: options.keepalive, mode: options.mode, redirect: options.redirect, referrer: options.referrer, referrerPolicy: options.referrerPolicy, // @ts-ignore - Next.js specific options next: options.next, // Node.js specific option agent: this.agent, }), timeoutMs); if (!response.ok) { const errorData = await response.json(); this.logger(logging_1.LogLevel.ERROR, "request error", { status: response.status, statusText: response.statusText, error: errorData, }); const error = new Error(errorData.error || "An error occurred"); this.emit("error", { error, request: { method, path, queryParams, }, }); throw error; } // Check if the response is JSON or text based on Content-Type header const contentType = response.headers.get("Content-Type"); if (contentType?.toLowerCase().includes("application/json")) { const jsonResponse = await response.json(); // If response has data field and no error, unwrap it, otherwise use the whole response const data = jsonResponse.data && !jsonResponse.error ? jsonResponse.data : jsonResponse; return data; } const text = await response.text(); return text; } catch (error) { this.logger(logging_1.LogLevel.ERROR, "request failed", { error }); // Emit error event this.emit("error", { error: error, request: { method, path, queryParams, }, }); throw error; } } async requestStream({ method, path, body, queryParams = {}, options = {} }) { this.logger(logging_1.LogLevel.DEBUG, "stream request start", { method, url: `${this.baseUrl}${path}`, queryParams, }); this.emit("request", { method, path, queryParams, }); const queryString = Object.entries(queryParams) .filter(([_, value]) => value !== undefined) .map(([key, value]) => { if (Array.isArray(value)) { return value.map((item) => `${encodeURIComponent(key)}=${encodeURIComponent(String(item))}`).join("&"); } return `${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`; }) .join("&"); const url = `${this.baseUrl}${path}${queryString ? `?${queryString}` : ""}`; const headers = { ...this.defaultHeaders, ...options.headers, "Accept": "text/event-stream", "Cache-Control": "no-cache", "Connection": "keep-alive", }; const timeoutMs = options.timeoutMs || this.timeoutMs; try { const response = await error_1.RequestTimeoutError.rejectAfterTimeout(this.fetchFn(url, { method, headers, body: body ? JSON.stringify(body) : undefined, signal: options.signal, cache: options.cache, credentials: options.credentials, integrity: options.integrity, keepalive: options.keepalive, mode: options.mode, redirect: options.redirect, referrer: options.referrer, referrerPolicy: options.referrerPolicy, // @ts-ignore - Next.js specific options next: options.next, // Node.js specific option agent: this.agent, }), timeoutMs); if (!response.ok) { const errorData = await response.json(); this.logger(logging_1.LogLevel.ERROR, "request error", { status: response.status, statusText: response.statusText, error: errorData, }); const error = new Error(errorData.error || "An error occurred"); this.emit("error", { error, request: { method, path, queryParams, }, }); throw error; } // For streaming responses, return a transformed stream that parses the chunks if (!response.body) { throw new Error("No reader available for streaming response"); } let buffer = ""; const decoder = new TextDecoder(); // Create a TransformStream that will parse the raw bytes into the expected type T const transformer = new TransformStream({ transform: async (chunk, controller) => { try { // Decode the chunk and add to buffer const text = decoder.decode(chunk, { stream: true }); buffer += text; // Process any complete lines in the buffer const lines = buffer.split("\n"); // Keep the last potentially incomplete line in the buffer buffer = lines.pop() || ""; for (const line of lines) { if (line.startsWith("data: ")) { const jsonData = line.slice(6).trim(); // Remove 'data: ' prefix // Skip [DONE] marker if (jsonData === "[DONE]") { continue; } if (jsonData) { try { const parsed = JSON.parse(jsonData); controller.enqueue(parsed); } catch (e) { this.logger(logging_1.LogLevel.ERROR, "Error parsing JSON from stream", { error: e, data: jsonData, }); } } } else if (line.trim() && !line.startsWith(":")) { // Try to parse non-empty lines that aren't comments try { const parsed = JSON.parse(line); controller.enqueue(parsed); } catch (e) { // Not JSON, might be part of a multi-line chunk if (line.trim()) { this.logger(logging_1.LogLevel.DEBUG, "Non-JSON line in stream", { line }); } } } } } catch (error) { this.logger(logging_1.LogLevel.ERROR, "Error processing stream chunk", { error }); controller.error(error); } }, flush: (controller) => { // Process any remaining data in the buffer if (buffer.trim()) { if (buffer.startsWith("data: ")) { const jsonData = buffer.slice(6).trim(); if (jsonData && jsonData !== "[DONE]") { try { const parsed = JSON.parse(jsonData); controller.enqueue(parsed); } catch (e) { this.logger(logging_1.LogLevel.ERROR, "Error parsing final JSON from stream", { error: e, data: jsonData, }); } } } } }, }); // Pipe the response body through our transformer return response.body.pipeThrough(transformer); } catch (error) { this.logger(logging_1.LogLevel.ERROR, "stream request failed", { error }); // Emit error event this.emit("error", { error: error, request: { method, path, queryParams, }, }); throw error; } } async requestWithMetadata({ method, path, body, queryParams = {}, options = {} }) { this.logger(logging_1.LogLevel.DEBUG, "request with metadata start", { method, url: `${this.baseUrl}${path}`, queryParams, }); // Emit request event this.emit("request", { method, path, queryParams, }); const queryString = Object.entries(queryParams) .filter(([_, value]) => value !== undefined) .map(([key, value]) => { // Handle array values if (Array.isArray(value)) { return value.map((item) => `${encodeURIComponent(key)}=${encodeURIComponent(String(item))}`).join("&"); } return `${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`; }) .join("&"); const url = `${this.baseUrl}${path}${queryString ? `?${queryString}` : ""}`; const headers = { ...this.defaultHeaders, ...options.headers, }; const timeoutMs = options.timeoutMs || this.timeoutMs; try { const response = await error_1.RequestTimeoutError.rejectAfterTimeout(this.fetchFn(url, { method, headers, body: body ? JSON.stringify(body) : undefined, signal: options.signal, cache: options.cache, credentials: options.credentials, integrity: options.integrity, keepalive: options.keepalive, mode: options.mode, redirect: options.redirect, referrer: options.referrer, referrerPolicy: options.referrerPolicy, // @ts-ignore - Next.js specific options next: options.next, // Node.js specific option agent: this.agent, }), timeoutMs); if (!response.ok) { const errorData = await response.json(); this.logger(logging_1.LogLevel.ERROR, "request with metadata error", { status: response.status, statusText: response.statusText, error: errorData, }); const error = new Error(errorData.error || "An error occurred"); // Emit error event this.emit("error", { error, request: { method, path, queryParams, }, }); throw error; } const responseData = await response.json(); this.logger(logging_1.LogLevel.DEBUG, "request with metadata success", { responseData, }); // Emit response event this.emit("response", { method, path, status: response.status, data: responseData, }); // If response has data field, return wrapped format, otherwise treat whole response as data return responseData.data !== undefined ? { data: responseData.data, metadata: responseData.metadata, } : { data: responseData, metadata: {}, }; } catch (error) { this.logger(logging_1.LogLevel.ERROR, "request with metadata failed", { error }); // Emit error event this.emit("error", { error: error, request: { method, path, queryParams, }, }); throw error; } } paginate(params, fetchPage, response, options) { // Convert PaginationResult to PaginationMetadata const metadata = response.metadata ? { page: response.metadata.page || 1, limit: response.metadata.limit || 10, total: response.metadata.total || 0, totalRows: response.metadata.total || 0, totalPages: Math.ceil((response.metadata.total || 0) / (response.metadata.limit || 10)), hasMore: response.metadata.hasMore || false, } : { page: 1, limit: 10, total: 0, totalRows: 0, totalPages: 0, hasMore: false, }; const currentPage = metadata.page; const hasNextPage = metadata.hasMore || false || currentPage < (metadata.totalPages || 0); const hasPreviousPage = currentPage > 1; // This method adds pagination helpers to the response const createPaginationHelpers = () => { return { hasNextPage, hasPreviousPage, nextPage: async () => { if (!hasNextPage) { return { data: response.data, metadata, ...createPaginationHelpers(), }; } const nextPage = currentPage + 1; const nextPageParams = { ...params, page: nextPage, }; try { const nextPageResponse = await fetchPage(nextPageParams, options); const nextPageMetadata = nextPageResponse.metadata ? { page: nextPageResponse.metadata.page || nextPage, limit: nextPageResponse.metadata.limit || metadata.limit, totalRows: nextPageResponse.metadata.total || metadata.totalRows || 0, totalPages: Math.ceil((nextPageResponse.metadata.total || metadata.totalRows || 0) / (nextPageResponse.metadata.limit || metadata.limit)), } : { page: nextPage, limit: metadata.limit, totalRows: metadata.totalRows || 0, totalPages: metadata.totalPages || 0, }; return { data: nextPageResponse.data, metadata: nextPageMetadata, ...createPaginationHelpers(), }; } catch (error) { throw new Error(`Error fetching next page: ${error}`); } }, previousPage: async () => { if (!hasPreviousPage) { return { data: response.data, metadata, ...createPaginationHelpers(), }; } const prevPage = currentPage - 1; const prevPageParams = { ...params, page: prevPage, }; try { const prevPageResponse = await fetchPage(prevPageParams, options); const prevPageMetadata = prevPageResponse.metadata ? { page: prevPageResponse.metadata.page || prevPage, limit: prevPageResponse.metadata.limit || metadata.limit, totalRows: prevPageResponse.metadata.total || metadata.totalRows || 0, totalPages: Math.ceil((prevPageResponse.metadata.total || metadata.totalRows || 0) / (prevPageResponse.metadata.limit || metadata.limit)), } : { page: prevPage, limit: metadata.limit, totalRows: metadata.totalRows || 0, totalPages: metadata.totalPages || 0, }; return { data: prevPageResponse.data, metadata: prevPageMetadata, ...createPaginationHelpers(), }; } catch (error) { throw new Error(`Error fetching previous page: ${error}`); } }, goToPage: async (page) => { if (page < 1 || (metadata.totalPages && page > metadata.totalPages)) { throw new Error(`Page ${page} is out of range. Valid range: 1-${metadata.totalPages || "?"}`); } const pageParams = { ...params, page, }; try { const pageResponse = await fetchPage(pageParams, options); const pageMetadata = pageResponse.metadata ? { page: pageResponse.metadata.page || page, limit: pageResponse.metadata.limit || metadata.limit, totalRows: pageResponse.metadata.total || metadata.totalRows || 0, totalPages: Math.ceil((pageResponse.metadata.total || metadata.totalRows || 0) / (pageResponse.metadata.limit || metadata.limit)), } : { page, limit: metadata.limit, totalRows: metadata.totalRows || 0, totalPages: metadata.totalPages || 0, }; return { data: pageResponse.data, metadata: pageMetadata, ...createPaginationHelpers(), }; } catch (error) { throw new Error(`Error fetching page ${page}: ${error}`); } }, getAllPages: async () => { if (!metadata.totalPages) { // If we don't know the total pages, just return the current page data return Array.isArray(response.data) ? response.data : [response.data]; } const allPages = []; const totalPages = metadata.totalPages || 1; // Add current page data if (Array.isArray(response.data)) { allPages.push(...response.data); } else { allPages.push(response.data); } // Fetch all other pages const pagePromises = []; for (let page = 1; page <= totalPages; page++) { if (page === currentPage) continue; // Skip current page const goToPageFn = this.paginate(params, fetchPage, response, options).goToPage; pagePromises.push(goToPageFn(page) .then((pageResponse) => { if (Array.isArray(pageResponse.data)) { return pageResponse.data; } return [pageResponse.data]; }) .catch(() => [])); } const pageResults = await Promise.all(pagePromises); for (const pageData of pageResults) { allPages.push(...pageData); } return allPages; }, }; }; return { data: response.data, metadata, error: response.error, ...createPaginationHelpers(), }; } } exports.MessariClient = MessariClient; //# sourceMappingURL=client.js.map