zerion-sdk
Advanced tools
Comparing version 0.0.5 to 0.0.6
import { iZerionAPI, iZerionUI } from "./types/interface"; | ||
import { ChainData, FungibleTokenData, PortfolioData, PositionData, UserBalanceOptions, UserDashboardResponse, FungibleOptions } from "./types"; | ||
import { ChainData, FungibleTokenData, PortfolioData, PositionData, UserBalanceOptions, UserDashboardResponse, FungibleOptions, NFTPosition, NFTPositionOptions } from "./types"; | ||
import { ZerionService } from "./services/zerion"; | ||
@@ -8,3 +8,3 @@ export declare class ZerionAPI implements iZerionAPI { | ||
readonly ui: iZerionUI; | ||
constructor(apiKey: string, testnet: boolean); | ||
constructor(apiKey: string, testnet?: boolean); | ||
getChains(): Promise<ChainData[]>; | ||
@@ -14,2 +14,3 @@ getPortfolio(walletAddress: string, currency?: string): Promise<PortfolioData>; | ||
fungibles(id: string): Promise<FungibleTokenData>; | ||
fetchNFTs(walletAddress: string, options?: NFTPositionOptions): Promise<NFTPosition[]>; | ||
} | ||
@@ -16,0 +17,0 @@ export declare class ZerionUI implements iZerionUI { |
@@ -9,4 +9,4 @@ "use strict"; | ||
class ZerionAPI { | ||
constructor(apiKey, testnet) { | ||
this.service = new zerion_1.ZerionService((0, util_1.isBase64)(apiKey) ? apiKey : (0, util_1.toBase64)(`${apiKey}:`), testnet ? "testnet" : undefined); | ||
constructor(apiKey, testnet = false) { | ||
this.service = new zerion_1.ZerionService(apiKey, testnet); | ||
this.isTestnet = testnet; | ||
@@ -32,2 +32,24 @@ this.ui = new ZerionUI(this); | ||
} | ||
async fetchNFTs(walletAddress, options) { | ||
if (this.isTestnet) { | ||
console.warn("This endpoint is not supported for testnet. Returning empty list"); | ||
return []; | ||
} | ||
// Base parameters | ||
const baseParams = { | ||
currency: options?.currency || "usd", | ||
"page[size]": options?.pageSize || 100, | ||
"filter[chain_ids]": options?.network, | ||
"filter[collection]": options?.collection, | ||
"filter[category]": options?.category, | ||
"filter[status]": options?.status, | ||
"page[number]": options?.pageNumber, | ||
sort: options?.sort, | ||
include: options?.include, | ||
}; | ||
const { data } = await this.service.fetchFromZerion( | ||
// TODO: Add pagination! | ||
`/wallets/${walletAddress}/nft-positions/?${(0, util_1.buildQueryString)(baseParams)}`); | ||
return data; | ||
} | ||
} | ||
@@ -34,0 +56,0 @@ exports.ZerionAPI = ZerionAPI; |
export declare class ZerionService { | ||
private readonly apiKey; | ||
private readonly env?; | ||
constructor(apiKey: string, env?: string | undefined); | ||
private readonly env; | ||
constructor(apiKey: string, testnet: boolean); | ||
fetchFromZerion<T>(endpoint: string): Promise<T>; | ||
} |
@@ -6,5 +6,7 @@ "use strict"; | ||
class ZerionService { | ||
constructor(apiKey, env) { | ||
this.apiKey = apiKey; | ||
this.env = env; | ||
constructor(apiKey, testnet) { | ||
this.apiKey = apiKey.startsWith("zk_") | ||
? Buffer.from(`${apiKey}:`).toString("base64") | ||
: apiKey; | ||
this.env = testnet ? "testnet" : undefined; | ||
} | ||
@@ -19,5 +21,4 @@ // Utility function to make API requests with error handling | ||
}; | ||
const response = await fetch(`${config_1.ZERION_CONFIG.BASE_URL}${endpoint}`, { | ||
headers, | ||
}); | ||
const url = `${config_1.ZERION_CONFIG.BASE_URL}${endpoint}`; | ||
const response = await fetch(url, { headers }); | ||
if (!response.ok) { | ||
@@ -24,0 +25,0 @@ throw new Error(`Failed to fetch ${endpoint}: ${response.statusText}`); |
@@ -1,2 +0,2 @@ | ||
import { ChainData, FungibleTokenData, PositionData, UserBalanceOptions, UserDashboardResponse } from "../types"; | ||
import { ChainData, FungibleTokenData, NFTPosition, PositionData, UserBalanceOptions, UserDashboardResponse, UserNftsResponse } from "../types"; | ||
export interface TransformOptions extends UserBalanceOptions { | ||
@@ -6,1 +6,2 @@ nativeTokens?: Record<string, FungibleTokenData>; | ||
export declare function transformPositionDataToUserDashboardResponse(positions: PositionData[], chains: ChainData[], options?: TransformOptions, isTestnet?: boolean): UserDashboardResponse; | ||
export declare function transformNftDataToUserNftResponse(positions: NFTPosition[], chains: ChainData[], options?: TransformOptions): UserNftsResponse; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.transformPositionDataToUserDashboardResponse = transformPositionDataToUserDashboardResponse; | ||
exports.transformNftDataToUserNftResponse = transformNftDataToUserNftResponse; | ||
// Transform position data to user dashboard response | ||
@@ -114,1 +115,54 @@ function transformPositionDataToUserDashboardResponse(positions, | ||
} | ||
// Transform NFT data to user NFTs response | ||
function transformNftDataToUserNftResponse(positions, | ||
// This part is only used for chain icons (it is basically static input) | ||
chains, options) { | ||
const chainsMap = (() => { | ||
const m = new Map(); | ||
chains.forEach((c) => { | ||
const numericId = parseInt(c.attributes.external_id, 16); | ||
if (!options?.supportedChains?.length || | ||
options.supportedChains.includes(numericId)) | ||
m.set(c.id, { | ||
name: c.attributes.name, | ||
icon: c.attributes.icon.url, | ||
numericId, | ||
}); | ||
}); | ||
return m; | ||
})(); | ||
const chainsSet = new Set(); | ||
const chainsIcons = {}; | ||
const nfts = positions.map((nft) => { | ||
const { detail, preview, video } = nft.attributes.nft_info.content; | ||
const media = detail?.url || preview?.url || video?.url || null; | ||
const chain = chainsMap.get(nft.relationships.chain.data.id); | ||
chainsSet.add(chain.name); | ||
chainsIcons[chain.name] = chain.icon; | ||
return { | ||
nft_contract_id: nft.attributes.nft_info.contract_address, | ||
token_id: nft.attributes.nft_info.token_id, | ||
minter: null, | ||
owner: null, | ||
base_uri: null, | ||
metadata_id: null, | ||
title: nft.attributes.nft_info.name, | ||
description: null, | ||
media, | ||
reference: null, | ||
reference_blob: null, | ||
minted_timestamp: null, | ||
last_transfer_timestamp: null, | ||
price: nft.attributes.price?.toString() || null, | ||
currency: null, | ||
chain: chain.name, | ||
chain_id: chain.numericId, | ||
}; | ||
}); | ||
return { | ||
nfts, | ||
totalNfts: nfts.length, | ||
chains: Array.from(chainsSet), | ||
chainsIcons, | ||
}; | ||
} |
@@ -14,1 +14,12 @@ export interface Links { | ||
}; | ||
export interface NFTPositionOptions { | ||
currency?: Currencies; | ||
network?: string | string[]; | ||
collection?: string; | ||
category?: "art" | "gaming" | "collectibles" | "other"; | ||
status?: "active" | "inactive"; | ||
pageNumber?: number; | ||
pageSize?: number; | ||
sort?: "name" | "-name" | "value" | "-value"; | ||
include?: "details" | "stats"; | ||
} |
@@ -8,1 +8,2 @@ export * from "./chains"; | ||
export * from "./fungibles"; | ||
export * from "./nfts"; |
@@ -24,1 +24,2 @@ "use strict"; | ||
__exportStar(require("./fungibles"), exports); | ||
__exportStar(require("./nfts"), exports); |
@@ -1,2 +0,2 @@ | ||
import { ChainData, PortfolioData, PositionData, UserBalanceOptions, UserDashboardResponse, FungibleOptions } from "."; | ||
import { ChainData, PortfolioData, PositionData, UserBalanceOptions, UserDashboardResponse, FungibleOptions, NFTPosition } from "."; | ||
export interface iZerionAPI { | ||
@@ -23,2 +23,8 @@ readonly ui: iZerionUI; | ||
getFungiblePositions(walletAddress: string, options?: FungibleOptions): Promise<PositionData[]>; | ||
/** | ||
* Fetches the NFT positions of a specific wallet. | ||
* @param walletAddress The wallet address whose NFT positions will be fetched. | ||
* @returns A promise resolving to the wallet's NFT positions. | ||
*/ | ||
fetchNFTs(walletAddress: string): Promise<NFTPosition[]>; | ||
} | ||
@@ -25,0 +31,0 @@ export interface iZerionUI { |
@@ -7,2 +7,26 @@ export type UserDashboardResponse = { | ||
}; | ||
export type UserNftsResponse = { | ||
nfts: UserNft[]; | ||
totalNfts: number; | ||
chains: string[]; | ||
chainsIcons: ChainIcons; | ||
}; | ||
export type UserNft = { | ||
nft_contract_id: string; | ||
token_id: string; | ||
minter: string | null; | ||
owner: string | null; | ||
base_uri: string | null; | ||
metadata_id: string | null; | ||
title: string; | ||
description: string | null; | ||
media: string | null; | ||
reference: string | null; | ||
reference_blob: Record<string, unknown> | null; | ||
minted_timestamp: string | null; | ||
last_transfer_timestamp: string | null; | ||
price: string | null; | ||
currency: string | null; | ||
chain: string | null; | ||
}; | ||
export type ChainIcons = { | ||
@@ -9,0 +33,0 @@ [key: string]: string; |
@@ -1,2 +0,1 @@ | ||
export declare function isBase64(str: string): boolean; | ||
export declare function toBase64(str: string): string; | ||
export declare function buildQueryString(params: Record<string, any>): string; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.isBase64 = isBase64; | ||
exports.toBase64 = toBase64; | ||
function isBase64(str) { | ||
if (!str) | ||
return false; // Handle empty string case | ||
try { | ||
const base64Regex = /^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)?$/; | ||
if (!base64Regex.test(str)) | ||
return false; | ||
const decoded = Buffer.from(str, "base64").toString("base64"); | ||
return decoded === str; | ||
exports.buildQueryString = buildQueryString; | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
function buildQueryString(params) { | ||
const query = {}; | ||
for (const [key, value] of Object.entries(params)) { | ||
if (value === undefined || value === null) | ||
continue; // Skip undefined or null values | ||
if (Array.isArray(value)) { | ||
query[key] = value.join(","); // Join arrays with commas | ||
} | ||
else { | ||
query[key] = value.toString(); | ||
} | ||
} | ||
catch { | ||
return false; | ||
} | ||
return new URLSearchParams(query).toString(); | ||
} | ||
function toBase64(str) { | ||
return Buffer.from(str).toString("base64"); | ||
} |
import { iZerionAPI, iZerionUI } from "./types/interface"; | ||
import { ChainData, FungibleTokenData, PortfolioData, PositionData, UserBalanceOptions, UserDashboardResponse, FungibleOptions } from "./types"; | ||
import { ChainData, FungibleTokenData, PortfolioData, PositionData, UserBalanceOptions, UserDashboardResponse, FungibleOptions, NFTPosition, NFTPositionOptions } from "./types"; | ||
import { ZerionService } from "./services/zerion"; | ||
@@ -8,3 +8,3 @@ export declare class ZerionAPI implements iZerionAPI { | ||
readonly ui: iZerionUI; | ||
constructor(apiKey: string, testnet: boolean); | ||
constructor(apiKey: string, testnet?: boolean); | ||
getChains(): Promise<ChainData[]>; | ||
@@ -14,2 +14,3 @@ getPortfolio(walletAddress: string, currency?: string): Promise<PortfolioData>; | ||
fungibles(id: string): Promise<FungibleTokenData>; | ||
fetchNFTs(walletAddress: string, options?: NFTPositionOptions): Promise<NFTPosition[]>; | ||
} | ||
@@ -16,0 +17,0 @@ export declare class ZerionUI implements iZerionUI { |
import { transformPositionDataToUserDashboardResponse } from "./transform/ui"; | ||
import { ZerionService } from "./services/zerion"; | ||
import { DEFAULT_FUNGIBLE_OPTIONS } from "./config"; | ||
import { isBase64, toBase64 } from "./util"; | ||
import { buildQueryString } from "./util"; | ||
export class ZerionAPI { | ||
@@ -9,4 +9,4 @@ service; | ||
ui; | ||
constructor(apiKey, testnet) { | ||
this.service = new ZerionService(isBase64(apiKey) ? apiKey : toBase64(`${apiKey}:`), testnet ? "testnet" : undefined); | ||
constructor(apiKey, testnet = false) { | ||
this.service = new ZerionService(apiKey, testnet); | ||
this.isTestnet = testnet; | ||
@@ -32,2 +32,24 @@ this.ui = new ZerionUI(this); | ||
} | ||
async fetchNFTs(walletAddress, options) { | ||
if (this.isTestnet) { | ||
console.warn("This endpoint is not supported for testnet. Returning empty list"); | ||
return []; | ||
} | ||
// Base parameters | ||
const baseParams = { | ||
currency: options?.currency || "usd", | ||
"page[size]": options?.pageSize || 100, | ||
"filter[chain_ids]": options?.network, | ||
"filter[collection]": options?.collection, | ||
"filter[category]": options?.category, | ||
"filter[status]": options?.status, | ||
"page[number]": options?.pageNumber, | ||
sort: options?.sort, | ||
include: options?.include, | ||
}; | ||
const { data } = await this.service.fetchFromZerion( | ||
// TODO: Add pagination! | ||
`/wallets/${walletAddress}/nft-positions/?${buildQueryString(baseParams)}`); | ||
return data; | ||
} | ||
} | ||
@@ -34,0 +56,0 @@ export class ZerionUI { |
export declare class ZerionService { | ||
private readonly apiKey; | ||
private readonly env?; | ||
constructor(apiKey: string, env?: string | undefined); | ||
private readonly env; | ||
constructor(apiKey: string, testnet: boolean); | ||
fetchFromZerion<T>(endpoint: string): Promise<T>; | ||
} |
@@ -5,5 +5,7 @@ import { ZERION_CONFIG } from "../config"; | ||
env; | ||
constructor(apiKey, env) { | ||
this.apiKey = apiKey; | ||
this.env = env; | ||
constructor(apiKey, testnet) { | ||
this.apiKey = apiKey.startsWith("zk_") | ||
? Buffer.from(`${apiKey}:`).toString("base64") | ||
: apiKey; | ||
this.env = testnet ? "testnet" : undefined; | ||
} | ||
@@ -18,5 +20,4 @@ // Utility function to make API requests with error handling | ||
}; | ||
const response = await fetch(`${ZERION_CONFIG.BASE_URL}${endpoint}`, { | ||
headers, | ||
}); | ||
const url = `${ZERION_CONFIG.BASE_URL}${endpoint}`; | ||
const response = await fetch(url, { headers }); | ||
if (!response.ok) { | ||
@@ -23,0 +24,0 @@ throw new Error(`Failed to fetch ${endpoint}: ${response.statusText}`); |
@@ -1,2 +0,2 @@ | ||
import { ChainData, FungibleTokenData, PositionData, UserBalanceOptions, UserDashboardResponse } from "../types"; | ||
import { ChainData, FungibleTokenData, NFTPosition, PositionData, UserBalanceOptions, UserDashboardResponse, UserNftsResponse } from "../types"; | ||
export interface TransformOptions extends UserBalanceOptions { | ||
@@ -6,1 +6,2 @@ nativeTokens?: Record<string, FungibleTokenData>; | ||
export declare function transformPositionDataToUserDashboardResponse(positions: PositionData[], chains: ChainData[], options?: TransformOptions, isTestnet?: boolean): UserDashboardResponse; | ||
export declare function transformNftDataToUserNftResponse(positions: NFTPosition[], chains: ChainData[], options?: TransformOptions): UserNftsResponse; |
@@ -111,1 +111,54 @@ // Transform position data to user dashboard response | ||
} | ||
// Transform NFT data to user NFTs response | ||
export function transformNftDataToUserNftResponse(positions, | ||
// This part is only used for chain icons (it is basically static input) | ||
chains, options) { | ||
const chainsMap = (() => { | ||
const m = new Map(); | ||
chains.forEach((c) => { | ||
const numericId = parseInt(c.attributes.external_id, 16); | ||
if (!options?.supportedChains?.length || | ||
options.supportedChains.includes(numericId)) | ||
m.set(c.id, { | ||
name: c.attributes.name, | ||
icon: c.attributes.icon.url, | ||
numericId, | ||
}); | ||
}); | ||
return m; | ||
})(); | ||
const chainsSet = new Set(); | ||
const chainsIcons = {}; | ||
const nfts = positions.map((nft) => { | ||
const { detail, preview, video } = nft.attributes.nft_info.content; | ||
const media = detail?.url || preview?.url || video?.url || null; | ||
const chain = chainsMap.get(nft.relationships.chain.data.id); | ||
chainsSet.add(chain.name); | ||
chainsIcons[chain.name] = chain.icon; | ||
return { | ||
nft_contract_id: nft.attributes.nft_info.contract_address, | ||
token_id: nft.attributes.nft_info.token_id, | ||
minter: null, | ||
owner: null, | ||
base_uri: null, | ||
metadata_id: null, | ||
title: nft.attributes.nft_info.name, | ||
description: null, | ||
media, | ||
reference: null, | ||
reference_blob: null, | ||
minted_timestamp: null, | ||
last_transfer_timestamp: null, | ||
price: nft.attributes.price?.toString() || null, | ||
currency: null, | ||
chain: chain.name, | ||
chain_id: chain.numericId, | ||
}; | ||
}); | ||
return { | ||
nfts, | ||
totalNfts: nfts.length, | ||
chains: Array.from(chainsSet), | ||
chainsIcons, | ||
}; | ||
} |
@@ -14,1 +14,12 @@ export interface Links { | ||
}; | ||
export interface NFTPositionOptions { | ||
currency?: Currencies; | ||
network?: string | string[]; | ||
collection?: string; | ||
category?: "art" | "gaming" | "collectibles" | "other"; | ||
status?: "active" | "inactive"; | ||
pageNumber?: number; | ||
pageSize?: number; | ||
sort?: "name" | "-name" | "value" | "-value"; | ||
include?: "details" | "stats"; | ||
} |
@@ -8,1 +8,2 @@ export * from "./chains"; | ||
export * from "./fungibles"; | ||
export * from "./nfts"; |
@@ -8,1 +8,2 @@ export * from "./chains"; | ||
export * from "./fungibles"; | ||
export * from "./nfts"; |
@@ -1,2 +0,2 @@ | ||
import { ChainData, PortfolioData, PositionData, UserBalanceOptions, UserDashboardResponse, FungibleOptions } from "."; | ||
import { ChainData, PortfolioData, PositionData, UserBalanceOptions, UserDashboardResponse, FungibleOptions, NFTPosition } from "."; | ||
export interface iZerionAPI { | ||
@@ -23,2 +23,8 @@ readonly ui: iZerionUI; | ||
getFungiblePositions(walletAddress: string, options?: FungibleOptions): Promise<PositionData[]>; | ||
/** | ||
* Fetches the NFT positions of a specific wallet. | ||
* @param walletAddress The wallet address whose NFT positions will be fetched. | ||
* @returns A promise resolving to the wallet's NFT positions. | ||
*/ | ||
fetchNFTs(walletAddress: string): Promise<NFTPosition[]>; | ||
} | ||
@@ -25,0 +31,0 @@ export interface iZerionUI { |
@@ -7,2 +7,26 @@ export type UserDashboardResponse = { | ||
}; | ||
export type UserNftsResponse = { | ||
nfts: UserNft[]; | ||
totalNfts: number; | ||
chains: string[]; | ||
chainsIcons: ChainIcons; | ||
}; | ||
export type UserNft = { | ||
nft_contract_id: string; | ||
token_id: string; | ||
minter: string | null; | ||
owner: string | null; | ||
base_uri: string | null; | ||
metadata_id: string | null; | ||
title: string; | ||
description: string | null; | ||
media: string | null; | ||
reference: string | null; | ||
reference_blob: Record<string, unknown> | null; | ||
minted_timestamp: string | null; | ||
last_transfer_timestamp: string | null; | ||
price: string | null; | ||
currency: string | null; | ||
chain: string | null; | ||
}; | ||
export type ChainIcons = { | ||
@@ -9,0 +33,0 @@ [key: string]: string; |
@@ -1,2 +0,1 @@ | ||
export declare function isBase64(str: string): boolean; | ||
export declare function toBase64(str: string): string; | ||
export declare function buildQueryString(params: Record<string, any>): string; |
@@ -1,17 +0,15 @@ | ||
export function isBase64(str) { | ||
if (!str) | ||
return false; // Handle empty string case | ||
try { | ||
const base64Regex = /^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)?$/; | ||
if (!base64Regex.test(str)) | ||
return false; | ||
const decoded = Buffer.from(str, "base64").toString("base64"); | ||
return decoded === str; | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
export function buildQueryString(params) { | ||
const query = {}; | ||
for (const [key, value] of Object.entries(params)) { | ||
if (value === undefined || value === null) | ||
continue; // Skip undefined or null values | ||
if (Array.isArray(value)) { | ||
query[key] = value.join(","); // Join arrays with commas | ||
} | ||
else { | ||
query[key] = value.toString(); | ||
} | ||
} | ||
catch { | ||
return false; | ||
} | ||
return new URLSearchParams(query).toString(); | ||
} | ||
export function toBase64(str) { | ||
return Buffer.from(str).toString("base64"); | ||
} |
{ | ||
"name": "zerion-sdk", | ||
"version": "0.0.5", | ||
"version": "0.0.6", | ||
"description": "A Typed Interface for ZerionAPI", | ||
@@ -5,0 +5,0 @@ "author": "bh2smith", |
56802
63
1641