UNPKG

@coinbase/cdp-sdk

Version:

SDK for interacting with the Coinbase Developer Platform Wallet API

190 lines (166 loc) 4.55 kB
import md5 from "md5"; import { UserInputValidationError } from "./errors.js"; import { APIError, NetworkError } from "./openapi-client/errors.js"; import { version } from "./version.js"; /** * The data in an error event */ type ErrorEventData = { /** * The API method where the error occurred, e.g. createAccount, getAccount */ method: string; /** * The error message */ message: string; /** * The error stack trace */ stack?: string; /** * The name of the event. This should match the name in AEC */ name: "error"; }; /** * The data in an action event */ type ActionEventData = { /** * The operation being performed, e.g. "transfer", "swap", "fund", "requestFaucet" */ action: string; /** * The account type, e.g. "evm-server", "evm-smart", "solana" */ accountType?: "evm_server" | "evm_smart" | "solana"; /** * Additional properties specific to the action */ properties?: Record<string, unknown>; /** * The name of the event */ name: "action"; }; type EventData = ErrorEventData | ActionEventData; // This is a public client id for the analytics service const publicClientId = "54f2ee2fb3d2b901a829940d70fbfc13"; export const Analytics = { identifier: "", // set in cdp.ts sendEvent, trackAction, trackError, }; /** * Sends an analytics event to the default endpoint * * @param event - The event data containing event-specific fields * @returns Promise that resolves when the event is sent */ async function sendEvent(event: EventData): Promise<void> { if (event.name === "error" && process.env.DISABLE_CDP_ERROR_REPORTING === "true") { return; } if (event.name !== "error" && process.env.DISABLE_CDP_USAGE_TRACKING === "true") { return; } const timestamp = Date.now(); const enhancedEvent = { user_id: Analytics.identifier, event_type: event.name, platform: "server", timestamp, event_properties: { project_name: "cdp-sdk", cdp_sdk_language: "typescript", version, ...event, }, }; const events = [enhancedEvent]; const stringifiedEventData = JSON.stringify(events); const uploadTime = timestamp.toString(); const checksum = md5(stringifiedEventData + uploadTime); const analyticsServiceData = { client: publicClientId, e: stringifiedEventData, checksum, }; const apiEndpoint = "https://cca-lite.coinbase.com"; const eventPath = "/amp"; const eventEndPoint = `${apiEndpoint}${eventPath}`; await fetch(eventEndPoint, { method: "POST", mode: "no-cors", headers: { "Content-Type": "application/json", }, body: JSON.stringify(analyticsServiceData), }); } /** * Track an action being performed * * @param params - The parameters for tracking an action * @param params.action - The action being performed * @param params.accountType - The type of account * @param params.properties - Additional properties */ function trackAction(params: { action: string; accountType?: "evm_server" | "evm_smart" | "solana"; properties?: Record<string, unknown>; }): void { if ( params.properties?.network && typeof params.properties.network === "string" && params.properties.network.startsWith("http") ) { const url = new URL(params.properties.network); params.properties.customRpcHost = url.hostname; params.properties.network = "custom"; } sendEvent({ action: params.action, accountType: params.accountType, properties: params.properties, name: "action", }).catch(() => { // ignore error }); } /** * Track an error that occurred in a method * * @param error - The error to track * @param method - The method name where the error occurred */ function trackError(error: unknown, method: string): void { if (process.env.DISABLE_CDP_ERROR_REPORTING === "true") return; if (!shouldTrackError(error)) return; const { message, stack } = error as Error; sendEvent({ method, message, stack, name: "error" }).catch(() => {}); } /** * Filters out non-errors and API errors * * @param error - The error to check. * @returns True if the error should be tracked, false otherwise. */ function shouldTrackError(error: unknown): boolean { if (!(error instanceof Error)) { return false; } if (error instanceof UserInputValidationError) { return false; } if (error instanceof NetworkError) { return true; } if (error instanceof APIError && error.errorType !== "unexpected_error") { return false; } return true; }