From 9098985d2603a7b741ed914b25af11b75a30d228 Mon Sep 17 00:00:00 2001 From: blake duncan Date: Wed, 10 Jun 2026 10:19:38 -0400 Subject: [PATCH 1/8] chore(data-apis): re-snapshot specs from docs main; add prices + token specs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Snapshots now pinned to alchemyplatform/docs main (becfd714) instead of a feature branch. prices (REST) and token (OpenRPC) enter the manifest so generation covers all five v1 spec sources; actions land in follow-ups. RPC emitter now strips non-root schema titles before compilation — title-named shared subschemas (e.g. token's Hex Encoded Address) otherwise hoist duplicate identifiers when one spec has multiple methods. Co-Authored-By: Claude Fable 5 --- packages/api-codegen/specs/portfolio.json | 24 +- packages/api-codegen/specs/prices.json | 1263 +++++++++++++++++ packages/api-codegen/specs/specs.lock.json | 8 +- packages/api-codegen/specs/token.json | 561 ++++++++ packages/api-codegen/src/rpc/openrpcWalker.ts | 30 +- packages/data-apis/codegen.manifest.ts | 40 + .../src/generated/rest/portfolio.types.ts | 24 +- .../src/generated/rest/prices.schema.ts | 68 + .../src/generated/rest/prices.types.ts | 735 ++++++++++ packages/data-apis/src/generated/rpc/token.ts | 105 ++ .../data-apis/src/generated/rpc/transfers.ts | 3 +- 11 files changed, 2830 insertions(+), 31 deletions(-) create mode 100644 packages/api-codegen/specs/prices.json create mode 100644 packages/api-codegen/specs/token.json create mode 100644 packages/data-apis/src/generated/rest/prices.schema.ts create mode 100644 packages/data-apis/src/generated/rest/prices.types.ts create mode 100644 packages/data-apis/src/generated/rpc/token.ts diff --git a/packages/api-codegen/specs/portfolio.json b/packages/api-codegen/specs/portfolio.json index 8a9d094209..a98cc8f98e 100644 --- a/packages/api-codegen/specs/portfolio.json +++ b/packages/api-codegen/specs/portfolio.json @@ -69,12 +69,12 @@ } }, "withMetadata": { - "description": "Boolean - if set to `true`, returns metadata. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`.", + "description": "Boolean - if set to `true`, returns metadata. Setting this to false will reduce payload size and may result in a faster API call.", "type": "boolean", "default": true }, "withPrices": { - "description": "Boolean - if set to `true`, returns token prices. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`.", + "description": "Boolean - if set to `true`, returns token prices. Setting this to false will reduce payload size and may result in a faster API call.", "type": "boolean", "default": true }, @@ -85,7 +85,7 @@ "default": true }, "includeErc20Tokens": { - "description": "Boolean - if set to `true`, returns ERC-20 tokens. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`.", + "description": "Boolean - if set to `true`, returns ERC-20 tokens. Setting this to false will reduce payload size and may result in a faster API call.", "type": "boolean", "default": true } @@ -348,7 +348,7 @@ "default": true }, "includeErc20Tokens": { - "description": "Boolean - if set to `true`, returns ERC-20 tokens. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`.", + "description": "Boolean - if set to `true`, returns ERC-20 tokens. Setting this to false will reduce payload size and may result in a faster API call.", "type": "boolean", "default": true } @@ -616,7 +616,7 @@ } }, "withMetadata": { - "description": "Boolean - if set to `true`, returns metadata. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`.", + "description": "Boolean - if set to `true`, returns metadata. Setting this to false will reduce payload size and may result in a faster API call.", "type": "boolean", "default": true }, @@ -1123,7 +1123,7 @@ } }, "withMetadata": { - "description": "Boolean - if set to `true`, returns metadata. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`.", + "description": "Boolean - if set to `true`, returns metadata. Setting this to false will reduce payload size and may result in a faster API call.", "type": "boolean", "default": true }, @@ -1507,7 +1507,7 @@ "default": true }, "includeErc20Tokens": { - "description": "Boolean - if set to `true`, returns ERC-20 tokens. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`.", + "description": "Boolean - if set to `true`, returns ERC-20 tokens. Setting this to false will reduce payload size and may result in a faster API call.", "type": "boolean", "default": true } @@ -1552,12 +1552,12 @@ } }, "withMetadata": { - "description": "Boolean - if set to `true`, returns metadata. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`.", + "description": "Boolean - if set to `true`, returns metadata. Setting this to false will reduce payload size and may result in a faster API call.", "type": "boolean", "default": true }, "withPrices": { - "description": "Boolean - if set to `true`, returns token prices. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`.", + "description": "Boolean - if set to `true`, returns token prices. Setting this to false will reduce payload size and may result in a faster API call.", "type": "boolean", "default": true }, @@ -1568,7 +1568,7 @@ "default": true }, "includeErc20Tokens": { - "description": "Boolean - if set to `true`, returns ERC-20 tokens. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`.", + "description": "Boolean - if set to `true`, returns ERC-20 tokens. Setting this to false will reduce payload size and may result in a faster API call.", "type": "boolean", "default": true } @@ -1679,7 +1679,7 @@ } }, "withMetadata": { - "description": "Boolean - if set to `true`, returns metadata. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`.", + "description": "Boolean - if set to `true`, returns metadata. Setting this to false will reduce payload size and may result in a faster API call.", "type": "boolean", "default": true }, @@ -1731,7 +1731,7 @@ } }, "withMetadata": { - "description": "Boolean - if set to `true`, returns metadata. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`.", + "description": "Boolean - if set to `true`, returns metadata. Setting this to false will reduce payload size and may result in a faster API call.", "type": "boolean", "default": true } diff --git a/packages/api-codegen/specs/prices.json b/packages/api-codegen/specs/prices.json new file mode 100644 index 0000000000..6c33d8d775 --- /dev/null +++ b/packages/api-codegen/specs/prices.json @@ -0,0 +1,1263 @@ +{ + "openapi": "3.1.0", + "info": { + "title": "📈 Prices API", + "version": "1.0" + }, + "servers": [ + { + "url": "https://api.g.alchemy.com/prices/v1" + } + ], + "paths": { + "/{apiKey}/tokens/by-symbol": { + "get": { + "summary": "Token Prices By Symbol", + "description": "Fetches current prices for multiple tokens using their symbols. Returns a list of token prices, each containing the symbol, prices, and an optional error field.\n", + "tags": [ + "Prices API Endpoints" + ], + "parameters": [ + { + "name": "apiKey", + "in": "path", + "required": true, + "schema": { + "type": "string", + "default": "docs-demo", + "description": "For higher throughput, [create your own API key](https://dashboard.alchemy.com/signup)." + } + }, + { + "in": "query", + "name": "symbols", + "required": true, + "description": "Array of token symbols (limit 25). Example: symbols=[ETH,BTC]\n", + "schema": { + "type": "array", + "minItems": 1, + "items": { + "type": "string", + "default": "ETH" + } + }, + "style": "form", + "explode": true + } + ], + "responses": { + "200": { + "description": "Successful response, even if some tokens are missing.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "array", + "description": "List of token price data.", + "items": { + "type": "object", + "properties": { + "symbol": { + "type": "string", + "description": "Token symbol." + }, + "prices": { + "type": "array", + "description": "List of price information.", + "items": { + "type": "object", + "properties": { + "currency": { + "type": "string", + "description": "Currency code (e.g., USD)." + }, + "value": { + "type": "string", + "description": "Price value as a string." + }, + "lastUpdatedAt": { + "type": "string", + "format": "date-time", + "description": "Time when the price was last updated." + } + }, + "required": [ + "currency", + "value", + "lastUpdatedAt" + ] + } + }, + "error": { + "type": "string", + "description": "Error message if applicable." + } + }, + "required": [ + "symbol", + "prices", + "error" + ] + } + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "description": "Bad Request: Malformed request or missing parameters.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "error": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Detailed error message." + } + }, + "required": [ + "message" + ], + "description": "Error details." + } + }, + "required": [ + "error" + ] + } + } + } + }, + "429": { + "description": "Too Many Requests: Rate limit exceeded.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "error": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Detailed error message." + } + }, + "required": [ + "message" + ], + "description": "Error details." + } + }, + "required": [ + "error" + ] + } + } + } + } + }, + "operationId": "get-token-prices-by-symbol" + } + }, + "/{apiKey}/tokens/by-address": { + "post": { + "summary": "Token Prices By Address", + "description": "Fetches current prices for multiple tokens using network and address pairs. Returns a list of token prices, each containing the network, address, prices, and an optional error field.\n", + "tags": [ + "Prices API Endpoints" + ], + "parameters": [ + { + "name": "apiKey", + "in": "path", + "required": true, + "schema": { + "type": "string", + "default": "docs-demo", + "description": "For higher throughput, [create your own API key](https://dashboard.alchemy.com/signup)." + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "addresses": { + "type": "array", + "minItems": 1, + "description": "Array of token network and address pairs (limit 25 addresses, max 3 networks). Networks should match network enums.\n", + "items": { + "type": "object", + "properties": { + "network": { + "type": "string", + "example": "eth-mainnet", + "default": "eth-mainnet", + "description": "Network identifier (e.g., eth-mainnet). Find more network enums [here](https://dashboard.alchemy.com/chains)" + }, + "address": { + "type": "string", + "description": "Token contract address.", + "example": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", + "default": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48" + } + }, + "required": [ + "network", + "address" + ] + }, + "maxItems": 25 + } + }, + "required": [ + "addresses" + ] + } + } + } + }, + "responses": { + "200": { + "description": "Successful response, even if some prices are missing.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "array", + "description": "List of token prices by address.", + "items": { + "type": "object", + "properties": { + "network": { + "type": "string", + "description": "Network identifier." + }, + "address": { + "type": "string", + "description": "Token contract address." + }, + "prices": { + "type": "array", + "description": "List of price information.", + "items": { + "type": "object", + "properties": { + "currency": { + "type": "string", + "description": "Currency code (e.g., USD)." + }, + "value": { + "type": "string", + "description": "Price value as a string." + }, + "lastUpdatedAt": { + "type": "string", + "format": "date-time", + "description": "Time when the price was last updated." + } + }, + "required": [ + "currency", + "value", + "lastUpdatedAt" + ] + } + }, + "error": { + "type": "string", + "description": "Error message if applicable." + } + }, + "required": [ + "network", + "address", + "prices", + "error" + ] + } + } + }, + "required": [ + "data" + ] + } + } + } + }, + "400": { + "description": "Bad Request: Invalid input (e.g., malformed JSON).", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "error": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Detailed error message." + } + }, + "required": [ + "message" + ], + "description": "Error details." + } + }, + "required": [ + "error" + ] + } + } + } + }, + "429": { + "description": "Too Many Requests: Rate limit exceeded.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "error": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Detailed error message." + } + }, + "required": [ + "message" + ], + "description": "Error details." + } + }, + "required": [ + "error" + ] + } + } + } + } + }, + "operationId": "get-token-prices-by-address" + } + }, + "/{apiKey}/tokens/historical": { + "post": { + "summary": "Historical Token Prices", + "description": "Provides historical price data for a single token over a time range. You can identify the token by symbol or by network and contract address.\n", + "tags": [ + "Prices API Endpoints" + ], + "parameters": [ + { + "name": "apiKey", + "in": "path", + "required": true, + "schema": { + "type": "string", + "default": "docs-demo", + "description": "For higher throughput, [create your own API key](https://dashboard.alchemy.com/signup)." + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "description": "Request body for fetching historical token prices. Provide either the token `symbol` or both `network` and `address`, along with the required time range parameters.\n", + "oneOf": [ + { + "required": [ + "symbol", + "startTime", + "endTime" + ], + "properties": { + "symbol": { + "type": "string", + "description": "Token symbol (e.g., ETH, BTC).", + "example": "ETH", + "default": "ETH" + }, + "startTime": { + "oneOf": [ + { + "type": "string", + "format": "date-time", + "description": "Start of the time range in ISO 8601 format.", + "default": "2024-01-01T00:00:00Z" + }, + { + "type": "number", + "description": "Start of the time range as a timestamp in seconds since epoch.", + "default": 1704067200 + } + ], + "description": "Start of the time range.", + "example": "2024-01-01T00:00:00Z" + }, + "endTime": { + "oneOf": [ + { + "type": "string", + "format": "date-time", + "description": "End of the time range in ISO 8601 format.", + "default": "2024-01-31T23:59:59Z" + }, + { + "type": "number", + "description": "End of the time range as a timestamp in seconds since epoch.", + "default": 1706745599 + } + ], + "description": "End of the time range.", + "example": "2024-01-31T23:59:59Z" + }, + "interval": { + "type": "string", + "description": "Time interval for data points. Max ranges: (5m, 7d), (1h, 30d), (1d, 1yr)\n", + "enum": [ + "5m", + "1h", + "1d" + ], + "default": "1d", + "example": "1d" + }, + "withMarketData": { + "type": "boolean", + "description": "Whether to include market cap and volume for each token", + "example": true, + "default": false + } + } + }, + { + "required": [ + "network", + "address", + "startTime", + "endTime" + ], + "properties": { + "network": { + "type": "string", + "description": "Network identifier (e.g., eth-mainnet).", + "example": "eth-mainnet", + "default": "eth-mainnet" + }, + "address": { + "type": "string", + "description": "Token contract address.", + "example": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", + "default": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48" + }, + "startTime": { + "oneOf": [ + { + "type": "string", + "format": "date-time", + "description": "Start of the time range in ISO 8601 format.", + "default": "2024-01-01T00:00:00Z" + }, + { + "type": "number", + "description": "Start of the time range as a timestamp since epoch.", + "default": 1704067200 + } + ], + "description": "Start of the time range.", + "example": "2024-01-01T00:00:00Z" + }, + "endTime": { + "oneOf": [ + { + "type": "string", + "format": "date-time", + "description": "End of the time range in ISO 8601 format.", + "default": "2024-01-31T23:59:59Z" + }, + { + "type": "number", + "description": "End of the time range as a timestamp since epoch.", + "default": 1706745599 + } + ], + "description": "End of the time range.", + "example": "2024-01-31T23:59:59Z" + }, + "interval": { + "type": "string", + "description": "Time interval for data points. Max ranges: (5m, 7d), (1h, 30d), (1d, 1yr)\n", + "enum": [ + "5m", + "1h", + "1d" + ], + "default": "1d", + "example": "1d" + }, + "withMarketData": { + "type": "boolean", + "description": "Whether to include market cap and volume for each token", + "example": true, + "default": false + } + } + } + ] + } + } + } + }, + "responses": { + "200": { + "description": "Successful response with historical price data.", + "content": { + "application/json": { + "schema": { + "type": "object", + "description": "Response containing historical price data. It will either include `symbol` or both `network` and `address` based on the request.\n", + "oneOf": [ + { + "type": "object", + "properties": { + "symbol": { + "type": "string", + "description": "Token symbol.", + "example": "ETH", + "default": "ETH" + }, + "currency": { + "type": "string", + "description": "Currency identifier.", + "example": "usd", + "default": "usd" + }, + "data": { + "type": "array", + "description": "List of historical price data points.", + "items": { + "type": "object", + "properties": { + "value": { + "type": "string", + "description": "Price value as a string.", + "example": "1900.00" + }, + "timestamp": { + "type": "string", + "format": "date-time", + "description": "Timestamp of the price data point.", + "example": "2024-01-01T00:00:00Z" + }, + "marketCap": { + "type": "string", + "description": "Total market capitalization at the timestamp", + "example": "274292310008.21802" + }, + "totalVolume": { + "type": "string", + "description": "Volume traded during the defined interval", + "example": "6715146404.608721" + } + }, + "required": [ + "value", + "timestamp" + ] + } + } + }, + "required": [ + "symbol", + "currency", + "data" + ] + }, + { + "type": "object", + "properties": { + "network": { + "type": "string", + "description": "Network identifier.", + "example": "eth-mainnet", + "default": "eth-mainnet" + }, + "address": { + "type": "string", + "description": "Token contract address.", + "example": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", + "default": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48" + }, + "currency": { + "type": "string", + "description": "Currency identifier.", + "example": "usd", + "default": "usd" + }, + "data": { + "type": "array", + "description": "List of historical price data points.", + "items": { + "type": "object", + "properties": { + "value": { + "type": "string", + "description": "Price value as a string.", + "example": "1900.00" + }, + "timestamp": { + "type": "string", + "format": "date-time", + "description": "Timestamp of the price data point.", + "example": "2024-01-01T00:00:00Z" + }, + "marketCap": { + "type": "string", + "description": "Total market capitalization at the timestamp", + "example": "274292310008.21802" + }, + "totalVolume": { + "type": "string", + "description": "Volume traded during the defined interval", + "example": "6715146404.608721" + } + }, + "required": [ + "value", + "timestamp" + ] + } + } + }, + "required": [ + "network", + "address", + "currency", + "data" + ] + } + ] + } + } + } + }, + "400": { + "description": "Bad Request: Invalid input (e.g., malformed request, missing parameters).", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "error": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Detailed error message." + } + }, + "required": [ + "message" + ], + "description": "Error details." + } + }, + "required": [ + "error" + ] + } + } + } + }, + "404": { + "description": "Not Found: Token not found.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "error": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Detailed error message." + } + }, + "required": [ + "message" + ], + "description": "Error details." + } + }, + "required": [ + "error" + ] + } + } + } + }, + "429": { + "description": "Too Many Requests: Rate limit exceeded.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "error": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Detailed error message." + } + }, + "required": [ + "message" + ], + "description": "Error details." + } + }, + "required": [ + "error" + ] + } + } + } + } + }, + "operationId": "get-historical-token-prices" + } + } + }, + "components": { + "securitySchemes": { + "apiKey": { + "type": "apiKey", + "name": "Authorization", + "in": "header", + "description": "An API key that will be supplied in a named header.", + "x-default": "Bearer API_KEY" + } + }, + "schemas": { + "TokenPricesResponse": { + "type": "object", + "properties": { + "data": { + "type": "array", + "description": "List of token price data.", + "items": { + "type": "object", + "properties": { + "symbol": { + "type": "string", + "description": "Token symbol." + }, + "prices": { + "type": "array", + "description": "List of price information.", + "items": { + "type": "object", + "properties": { + "currency": { + "type": "string", + "description": "Currency code (e.g., USD)." + }, + "value": { + "type": "string", + "description": "Price value as a string." + }, + "lastUpdatedAt": { + "type": "string", + "format": "date-time", + "description": "Time when the price was last updated." + } + }, + "required": [ + "currency", + "value", + "lastUpdatedAt" + ] + } + }, + "error": { + "type": "string", + "description": "Error message if applicable." + } + }, + "required": [ + "symbol", + "prices", + "error" + ] + } + } + }, + "required": [ + "data" + ] + }, + "TokenPriceResponseItem": { + "type": "object", + "properties": { + "symbol": { + "type": "string", + "description": "Token symbol." + }, + "prices": { + "type": "array", + "description": "List of price information.", + "items": { + "type": "object", + "properties": { + "currency": { + "type": "string", + "description": "Currency code (e.g., USD)." + }, + "value": { + "type": "string", + "description": "Price value as a string." + }, + "lastUpdatedAt": { + "type": "string", + "format": "date-time", + "description": "Time when the price was last updated." + } + }, + "required": [ + "currency", + "value", + "lastUpdatedAt" + ] + } + }, + "error": { + "type": "string", + "description": "Error message if applicable." + } + }, + "required": [ + "symbol", + "prices", + "error" + ] + }, + "ByAddressRequest": { + "type": "object", + "properties": { + "addresses": { + "type": "array", + "minItems": 1, + "description": "Array of token network and address pairs (limit 25 addresses, max 3 networks). Networks should match network enums.\n", + "items": { + "type": "object", + "properties": { + "network": { + "type": "string", + "example": "eth-mainnet", + "default": "eth-mainnet", + "description": "Network identifier (e.g., eth-mainnet). Find more network enums [here](https://dashboard.alchemy.com/chains)" + }, + "address": { + "type": "string", + "description": "Token contract address.", + "example": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", + "default": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48" + } + }, + "required": [ + "network", + "address" + ] + }, + "maxItems": 25 + } + }, + "required": [ + "addresses" + ] + }, + "AddressPricesResponse": { + "type": "object", + "properties": { + "data": { + "type": "array", + "description": "List of token prices by address.", + "items": { + "type": "object", + "properties": { + "network": { + "type": "string", + "description": "Network identifier." + }, + "address": { + "type": "string", + "description": "Token contract address." + }, + "prices": { + "type": "array", + "description": "List of price information.", + "items": { + "type": "object", + "properties": { + "currency": { + "type": "string", + "description": "Currency code (e.g., USD)." + }, + "value": { + "type": "string", + "description": "Price value as a string." + }, + "lastUpdatedAt": { + "type": "string", + "format": "date-time", + "description": "Time when the price was last updated." + } + }, + "required": [ + "currency", + "value", + "lastUpdatedAt" + ] + } + }, + "error": { + "type": "string", + "description": "Error message if applicable." + } + }, + "required": [ + "network", + "address", + "prices", + "error" + ] + } + } + }, + "required": [ + "data" + ] + }, + "AddressPriceResponseItem": { + "type": "object", + "properties": { + "network": { + "type": "string", + "description": "Network identifier." + }, + "address": { + "type": "string", + "description": "Token contract address." + }, + "prices": { + "type": "array", + "description": "List of price information.", + "items": { + "type": "object", + "properties": { + "currency": { + "type": "string", + "description": "Currency code (e.g., USD)." + }, + "value": { + "type": "string", + "description": "Price value as a string." + }, + "lastUpdatedAt": { + "type": "string", + "format": "date-time", + "description": "Time when the price was last updated." + } + }, + "required": [ + "currency", + "value", + "lastUpdatedAt" + ] + } + }, + "error": { + "type": "string", + "description": "Error message if applicable." + } + }, + "required": [ + "network", + "address", + "prices", + "error" + ] + }, + "HistoricalPricesResponse": { + "type": "object", + "description": "Response containing historical price data. It will either include `symbol` or both `network` and `address` based on the request.\n", + "oneOf": [ + { + "type": "object", + "properties": { + "symbol": { + "type": "string", + "description": "Token symbol.", + "example": "ETH", + "default": "ETH" + }, + "currency": { + "type": "string", + "description": "Currency identifier.", + "example": "usd", + "default": "usd" + }, + "data": { + "type": "array", + "description": "List of historical price data points.", + "items": { + "type": "object", + "properties": { + "value": { + "type": "string", + "description": "Price value as a string.", + "example": "1900.00" + }, + "timestamp": { + "type": "string", + "format": "date-time", + "description": "Timestamp of the price data point.", + "example": "2024-01-01T00:00:00Z" + }, + "marketCap": { + "type": "string", + "description": "Total market capitalization at the timestamp", + "example": "274292310008.21802" + }, + "totalVolume": { + "type": "string", + "description": "Volume traded during the defined interval", + "example": "6715146404.608721" + } + }, + "required": [ + "value", + "timestamp" + ] + } + } + }, + "required": [ + "symbol", + "currency", + "data" + ] + }, + { + "type": "object", + "properties": { + "network": { + "type": "string", + "description": "Network identifier.", + "example": "eth-mainnet", + "default": "eth-mainnet" + }, + "address": { + "type": "string", + "description": "Token contract address.", + "example": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", + "default": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48" + }, + "currency": { + "type": "string", + "description": "Currency identifier.", + "example": "usd", + "default": "usd" + }, + "data": { + "type": "array", + "description": "List of historical price data points.", + "items": { + "type": "object", + "properties": { + "value": { + "type": "string", + "description": "Price value as a string.", + "example": "1900.00" + }, + "timestamp": { + "type": "string", + "format": "date-time", + "description": "Timestamp of the price data point.", + "example": "2024-01-01T00:00:00Z" + }, + "marketCap": { + "type": "string", + "description": "Total market capitalization at the timestamp", + "example": "274292310008.21802" + }, + "totalVolume": { + "type": "string", + "description": "Volume traded during the defined interval", + "example": "6715146404.608721" + } + }, + "required": [ + "value", + "timestamp" + ] + } + } + }, + "required": [ + "network", + "address", + "currency", + "data" + ] + } + ] + }, + "HistoricalPricesBySymbol": { + "type": "object", + "properties": { + "symbol": { + "type": "string", + "description": "Token symbol.", + "example": "ETH", + "default": "ETH" + }, + "currency": { + "type": "string", + "description": "Currency identifier.", + "example": "usd", + "default": "usd" + }, + "data": { + "type": "array", + "description": "List of historical price data points.", + "items": { + "type": "object", + "properties": { + "value": { + "type": "string", + "description": "Price value as a string.", + "example": "1900.00" + }, + "timestamp": { + "type": "string", + "format": "date-time", + "description": "Timestamp of the price data point.", + "example": "2024-01-01T00:00:00Z" + }, + "marketCap": { + "type": "string", + "description": "Total market capitalization at the timestamp", + "example": "274292310008.21802" + }, + "totalVolume": { + "type": "string", + "description": "Volume traded during the defined interval", + "example": "6715146404.608721" + } + }, + "required": [ + "value", + "timestamp" + ] + } + } + }, + "required": [ + "symbol", + "currency", + "data" + ] + }, + "HistoricalPricesByAddress": { + "type": "object", + "properties": { + "network": { + "type": "string", + "description": "Network identifier.", + "example": "eth-mainnet", + "default": "eth-mainnet" + }, + "address": { + "type": "string", + "description": "Token contract address.", + "example": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", + "default": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48" + }, + "currency": { + "type": "string", + "description": "Currency identifier.", + "example": "usd", + "default": "usd" + }, + "data": { + "type": "array", + "description": "List of historical price data points.", + "items": { + "type": "object", + "properties": { + "value": { + "type": "string", + "description": "Price value as a string.", + "example": "1900.00" + }, + "timestamp": { + "type": "string", + "format": "date-time", + "description": "Timestamp of the price data point.", + "example": "2024-01-01T00:00:00Z" + }, + "marketCap": { + "type": "string", + "description": "Total market capitalization at the timestamp", + "example": "274292310008.21802" + }, + "totalVolume": { + "type": "string", + "description": "Volume traded during the defined interval", + "example": "6715146404.608721" + } + }, + "required": [ + "value", + "timestamp" + ] + } + } + }, + "required": [ + "network", + "address", + "currency", + "data" + ] + } + } + } +} diff --git a/packages/api-codegen/specs/specs.lock.json b/packages/api-codegen/specs/specs.lock.json index c6953038ec..9302ddfc41 100644 --- a/packages/api-codegen/specs/specs.lock.json +++ b/packages/api-codegen/specs/specs.lock.json @@ -1,12 +1,14 @@ { "docs": { "repository": "alchemyplatform/docs", - "sha": "374030e02046972b4158612036af3aed9130b675", - "branch": "codex/improve-agent-wallet-docs" + "sha": "becfd7140371eb947dc0bcfe826922493ce6a48d", + "branch": "HEAD" }, "specs": { "nft.json": "c90282cfc4959f48534aaccceccdd31202ca1410888d7d0daafdd20e0f8c4885", - "portfolio.json": "16bad2001183fada4147f445640555e22a0c58ad44844eefdf0a06e3f794774c", + "portfolio.json": "7d5aee47eab3856186d9d323788e1721277a20aa2622e78659dd721fc2577d85", + "prices.json": "febf3652f81e6053bd19994c66f9f5709ce25d18f3ff8cddd7d5e173f5a3bdc0", + "token.json": "2a5b02c5400909e7670fb59b6b77b1c1d75f0275155d1ff9c24c5c21c985dda5", "transfers.json": "17626a215d7453b41a868e434d5d86a9a1505d8e648ca91c7df1b44c97af9cf5" } } diff --git a/packages/api-codegen/specs/token.json b/packages/api-codegen/specs/token.json new file mode 100644 index 0000000000..51af78aebe --- /dev/null +++ b/packages/api-codegen/specs/token.json @@ -0,0 +1,561 @@ +{ + "$schema": "https://meta.open-rpc.org/", + "openrpc": "1.2.4", + "info": { + "title": "Alchemy Token JSON-RPC Specification", + "description": "A specification of the standard JSON-RPC methods for Token API.", + "version": "0.0.0" + }, + "servers": [ + { + "url": "https://eth-mainnet.g.alchemy.com/v2", + "name": "Ethereum Mainnet" + }, + { + "url": "https://eth-mainnetbeacon.g.alchemy.com/v2", + "name": "Ethereum Mainnet Beacon" + }, + { + "url": "https://eth-hoodi.g.alchemy.com/v2", + "name": "Ethereum Hoodi" + }, + { + "url": "https://eth-hoodibeacon.g.alchemy.com/v2", + "name": "Ethereum Hoodi Beacon" + }, + { + "url": "https://eth-sepolia.g.alchemy.com/v2", + "name": "Ethereum Sepolia" + }, + { + "url": "https://eth-sepoliabeacon.g.alchemy.com/v2", + "name": "Ethereum Sepolia Beacon" + }, + { + "url": "https://abstract-mainnet.g.alchemy.com/v2", + "name": "Abstract Mainnet" + }, + { + "url": "https://abstract-testnet.g.alchemy.com/v2", + "name": "Abstract Testnet" + }, + { + "url": "https://anime-mainnet.g.alchemy.com/v2", + "name": "Anime Mainnet" + }, + { + "url": "https://anime-sepolia.g.alchemy.com/v2", + "name": "Anime Sepolia" + }, + { + "url": "https://apechain-mainnet.g.alchemy.com/v2", + "name": "ApeChain Mainnet" + }, + { + "url": "https://apechain-curtis.g.alchemy.com/v2", + "name": "ApeChain Curtis" + }, + { + "url": "https://arb-mainnet.g.alchemy.com/v2", + "name": "Arbitrum Mainnet" + }, + { + "url": "https://arb-sepolia.g.alchemy.com/v2", + "name": "Arbitrum Sepolia" + }, + { + "url": "https://avax-mainnet.g.alchemy.com/v2", + "name": "Avalanche Mainnet" + }, + { + "url": "https://avax-fuji.g.alchemy.com/v2", + "name": "Avalanche Fuji" + }, + { + "url": "https://base-mainnet.g.alchemy.com/v2", + "name": "Base Mainnet" + }, + { + "url": "https://base-sepolia.g.alchemy.com/v2", + "name": "Base Sepolia" + }, + { + "url": "https://berachain-mainnet.g.alchemy.com/v2", + "name": "Berachain Mainnet" + }, + { + "url": "https://berachain-bepolia.g.alchemy.com/v2", + "name": "Berachain Bepolia" + }, + { + "url": "https://blast-mainnet.g.alchemy.com/v2", + "name": "Blast Mainnet" + }, + { + "url": "https://blast-sepolia.g.alchemy.com/v2", + "name": "Blast Sepolia" + }, + { + "url": "https://bnb-mainnet.g.alchemy.com/v2", + "name": "BNB Smart Chain Mainnet" + }, + { + "url": "https://bnb-testnet.g.alchemy.com/v2", + "name": "BNB Smart Chain Testnet" + }, + { + "url": "https://celo-mainnet.g.alchemy.com/v2", + "name": "Celo Mainnet" + }, + { + "url": "https://celo-sepolia.g.alchemy.com/v2", + "name": "Celo Sepolia" + }, + { + "url": "https://gensyn-mainnet.g.alchemy.com/v2", + "name": "Gensyn Mainnet" + }, + { + "url": "https://gensyn-testnet.g.alchemy.com/v2", + "name": "Gensyn Testnet" + }, + { + "url": "https://gnosis-mainnet.g.alchemy.com/v2", + "name": "Gnosis Mainnet" + }, + { + "url": "https://gnosis-chiado.g.alchemy.com/v2", + "name": "Gnosis Chiado" + }, + { + "url": "https://hyperliquid-mainnet.g.alchemy.com/v2", + "name": "Hyperliquid Mainnet" + }, + { + "url": "https://hyperliquid-testnet.g.alchemy.com/v2", + "name": "Hyperliquid Testnet" + }, + { + "url": "https://ink-mainnet.g.alchemy.com/v2", + "name": "Ink Mainnet" + }, + { + "url": "https://ink-sepolia.g.alchemy.com/v2", + "name": "Ink Sepolia" + }, + { + "url": "https://lens-mainnet.g.alchemy.com/v2", + "name": "Lens Mainnet" + }, + { + "url": "https://lens-sepolia.g.alchemy.com/v2", + "name": "Lens Sepolia" + }, + { + "url": "https://linea-mainnet.g.alchemy.com/v2", + "name": "Linea Mainnet" + }, + { + "url": "https://linea-sepolia.g.alchemy.com/v2", + "name": "Linea Sepolia" + }, + { + "url": "https://polygon-mainnet.g.alchemy.com/v2", + "name": "Polygon Mainnet" + }, + { + "url": "https://polygon-amoy.g.alchemy.com/v2", + "name": "Polygon Amoy" + }, + { + "url": "https://monad-mainnet.g.alchemy.com/v2", + "name": "Monad Mainnet" + }, + { + "url": "https://monad-testnet.g.alchemy.com/v2", + "name": "Monad Testnet" + }, + { + "url": "https://mythos-mainnet.g.alchemy.com/v2", + "name": "Mythos Mainnet" + }, + { + "url": "https://opt-mainnet.g.alchemy.com/v2", + "name": "OP Mainnet Mainnet" + }, + { + "url": "https://opt-sepolia.g.alchemy.com/v2", + "name": "OP Mainnet Sepolia" + }, + { + "url": "https://robinhood-testnet.g.alchemy.com/v2", + "name": "Robinhood Chain Testnet" + }, + { + "url": "https://ronin-mainnet.g.alchemy.com/v2", + "name": "Ronin Mainnet" + }, + { + "url": "https://ronin-saigon.g.alchemy.com/v2", + "name": "Ronin Saigon" + }, + { + "url": "https://rootstock-mainnet.g.alchemy.com/v2", + "name": "Rootstock Mainnet" + }, + { + "url": "https://rootstock-testnet.g.alchemy.com/v2", + "name": "Rootstock Testnet" + }, + { + "url": "https://scroll-mainnet.g.alchemy.com/v2", + "name": "Scroll Mainnet" + }, + { + "url": "https://scroll-sepolia.g.alchemy.com/v2", + "name": "Scroll Sepolia" + }, + { + "url": "https://settlus-mainnet.g.alchemy.com/v2", + "name": "Settlus Mainnet" + }, + { + "url": "https://settlus-septestnet.g.alchemy.com/v2", + "name": "Settlus Sepolia" + }, + { + "url": "https://shape-mainnet.g.alchemy.com/v2", + "name": "Shape Mainnet" + }, + { + "url": "https://shape-sepolia.g.alchemy.com/v2", + "name": "Shape Sepolia" + }, + { + "url": "https://soneium-mainnet.g.alchemy.com/v2", + "name": "Soneium Mainnet" + }, + { + "url": "https://soneium-minato.g.alchemy.com/v2", + "name": "Soneium Minato" + }, + { + "url": "https://story-mainnet.g.alchemy.com/v2", + "name": "Story Mainnet" + }, + { + "url": "https://story-aeneid.g.alchemy.com/v2", + "name": "Story Aeneid" + }, + { + "url": "https://unichain-mainnet.g.alchemy.com/v2", + "name": "Unichain Mainnet" + }, + { + "url": "https://unichain-sepolia.g.alchemy.com/v2", + "name": "Unichain Sepolia" + }, + { + "url": "https://worldchain-mainnet.g.alchemy.com/v2", + "name": "World Chain Mainnet" + }, + { + "url": "https://worldchain-sepolia.g.alchemy.com/v2", + "name": "World Chain Sepolia" + }, + { + "url": "https://zetachain-mainnet.g.alchemy.com/v2", + "name": "ZetaChain Mainnet" + }, + { + "url": "https://zetachain-testnet.g.alchemy.com/v2", + "name": "ZetaChain Testnet" + }, + { + "url": "https://zksync-mainnet.g.alchemy.com/v2", + "name": "ZKsync Mainnet" + }, + { + "url": "https://zksync-sepolia.g.alchemy.com/v2", + "name": "ZKsync Sepolia" + }, + { + "url": "https://zora-mainnet.g.alchemy.com/v2", + "name": "Zora Mainnet" + }, + { + "url": "https://zora-sepolia.g.alchemy.com/v2", + "name": "Zora Sepolia" + } + ], + "methods": [ + { + "name": "alchemy_getTokenAllowance", + "description": "Returns the token allowance by spender for a given owner.", + "x-compute-units": 20, + "params": [ + { + "name": "tokenAllowanceRequest", + "required": true, + "description": "An object specifying the token contract address, the owner address, and the spender address.\n", + "schema": { + "type": "object", + "required": [ + "contract", + "owner", + "spender" + ], + "properties": { + "contract": { + "description": "20-byte token contract address.", + "title": "hex encoded address", + "type": "string", + "pattern": "^0x[0-9a-fA-F]{40}$" + }, + "owner": { + "description": "20-byte address of the owner.", + "title": "hex encoded address", + "type": "string", + "pattern": "^0x[0-9a-fA-F]{40}$" + }, + "spender": { + "description": "20-byte address of the spender.", + "title": "hex encoded address", + "type": "string", + "pattern": "^0x[0-9a-fA-F]{40}$" + } + } + } + } + ], + "result": { + "name": "Allowance", + "description": "The amount that the spender is allowed to withdraw from the owner.", + "schema": { + "type": "string", + "description": "A decimal string representing the allowance." + } + }, + "examples": [ + { + "name": "Basic allowance example", + "params": [ + { + "name": "tokenAllowanceRequest", + "value": { + "contract": "0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270", + "owner": "0xf1a726210550c306a9964b251cbcd3fa5ecb275d", + "spender": "0xdef1c0ded9bec7f1a1670819833240f027b25eff" + } + } + ], + "result": { + "name": "Allowance", + "value": "0" + } + } + ] + }, + { + "name": "alchemy_getTokenBalances", + "description": "Returns ERC-20 token balances for a given address.", + "x-compute-units": 20, + "params": [ + { + "name": "address", + "required": true, + "description": "A 20-byte wallet address.\n", + "schema": { + "type": "string", + "title": "Address", + "default": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" + } + }, + { + "name": "tokenSpec", + "required": false, + "description": "A token specification: - The string \"erc20\" - \"NATIVE_TOKEN\" - \"DEFAULT_TOKENS\" (deprecated) - An array of token contract addresses.\n", + "schema": { + "oneOf": [ + { + "type": "string", + "title": "Token Specification", + "enum": [ + "erc20", + "DEFAULT_TOKENS", + "NATIVE_TOKEN" + ], + "default": "erc20" + }, + { + "type": "array", + "title": "Array of Contract Addresses", + "items": { + "type": "string", + "pattern": "^0[xX][0-9a-fA-F]{40}$" + } + } + ] + } + }, + { + "name": "options", + "required": false, + "description": "Optional pagination options.\n", + "schema": { + "type": "object", + "title": "Options", + "properties": { + "pageKey": { + "type": "string", + "description": "Used for pagination if more results are available." + }, + "maxCount": { + "type": "integer", + "description": "Maximum number of token balances to return per call (capped at 100).", + "default": 100 + } + } + } + } + ], + "result": { + "name": "Token Balances", + "description": "An object containing the queried address and an array of token balance objects.", + "schema": { + "type": "object", + "properties": { + "address": { + "description": "Address for which token balances were returned.", + "title": "hex encoded address", + "type": "string", + "pattern": "^0x[0-9a-fA-F]{40}$" + }, + "tokenBalances": { + "type": "array", + "description": "Array of token balance objects. Exactly one of tokenBalance or error is non-null.", + "items": { + "type": "object", + "properties": { + "contractAddress": { + "description": "The ERC-20 contract address.", + "title": "hex encoded address", + "type": "string", + "pattern": "^0x[0-9a-fA-F]{40}$" + }, + "tokenBalance": { + "type": "string", + "description": "Hex-encoded string of the token balance, or null if error is present." + } + } + } + } + } + } + }, + "examples": [ + { + "name": "Single token balance example", + "params": [ + { + "name": "address", + "value": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" + }, + { + "name": "tokenSpec", + "value": [ + "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48" + ] + } + ], + "result": { + "name": "Token Balances", + "value": { + "address": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", + "tokenBalances": [ + { + "contractAddress": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", + "tokenBalance": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + ] + } + } + } + ] + }, + { + "name": "alchemy_getTokenMetadata", + "description": "Returns metadata for a given token contract (name, symbol, decimals, logo).", + "x-compute-units": 10, + "params": [ + { + "name": "contractAddress", + "required": true, + "description": "A single 20-byte token contract address.", + "schema": { + "title": "hex encoded address", + "type": "string", + "pattern": "^0x[0-9a-fA-F]{40}$" + } + } + ], + "result": { + "name": "Token Metadata", + "description": "Object with name, symbol, decimals, and an optional logo URL.", + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Token's name, or null if not found." + }, + "symbol": { + "type": "string", + "description": "Token's symbol, or null if not found." + }, + "decimals": { + "type": "number", + "description": "Number of decimals the token uses, or null if not found." + }, + "logo": { + "type": "string", + "description": "URL of the token's logo image, or null if none available." + } + } + } + }, + "examples": [ + { + "name": "USDC metadata example", + "params": [ + { + "name": "contractAddress", + "value": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48" + } + ], + "result": { + "name": "Token Metadata", + "value": { + "name": "USD Coin", + "symbol": "USDC", + "decimals": 6, + "logo": "https://static.alchemyapi.io/images/assets/3408.png" + } + } + } + ] + } + ], + "x-auth-params": [ + { + "name": "apiKey", + "in": "path", + "schema": { + "type": "string", + "default": "docs-demo", + "description": "For higher throughput, [create your own API key](https://dashboard.alchemy.com/signup)" + }, + "required": true + } + ] +} diff --git a/packages/api-codegen/src/rpc/openrpcWalker.ts b/packages/api-codegen/src/rpc/openrpcWalker.ts index 481b8985cf..c8abc9fe2f 100644 --- a/packages/api-codegen/src/rpc/openrpcWalker.ts +++ b/packages/api-codegen/src/rpc/openrpcWalker.ts @@ -41,6 +41,32 @@ export function closeObjectSchemas(node: unknown): unknown { return copy; } +/** + * Recursively removes `title` from schema nodes. json-schema-to-typescript + * hoists title-named subschemas as standalone exported types; when multiple + * methods in one spec share a titled subschema (e.g. "Hex Encoded Address"), + * per-method compilation emits duplicate identifiers. Stripping titles inlines + * the subschemas instead — generated internals don't need the pretty names. + * The emitter re-applies a root title to pin the exported type name. + * + * @param {unknown} node A JSON Schema node (or fragment) + * @returns {unknown} A deep copy without title fields + */ +export function stripTitles(node: unknown): unknown { + if (Array.isArray(node)) { + return node.map(stripTitles); + } + if (node === null || typeof node !== "object") { + return node; + } + const copy: Record = {}; + for (const [key, value] of Object.entries(node)) { + if (key === "title") continue; + copy[key] = stripTitles(value); + } + return copy; +} + /** * Extracts a method's param and result schemas from a bundled (dereferenced) * OpenRPC document, with object schemas closed for clean type compilation. @@ -73,7 +99,7 @@ export function extractMethod( return { name: param.name ?? `param${index}`, required: param.required === true, - schema: closeObjectSchemas(param.schema) as JsonSchema, + schema: stripTitles(closeObjectSchemas(param.schema)) as JsonSchema, }; }); @@ -84,6 +110,6 @@ export function extractMethod( return { name: methodName, params, - result: closeObjectSchemas(method.result.schema) as JsonSchema, + result: stripTitles(closeObjectSchemas(method.result.schema)) as JsonSchema, }; } diff --git a/packages/data-apis/codegen.manifest.ts b/packages/data-apis/codegen.manifest.ts index ce041ddaaf..c35720042b 100644 --- a/packages/data-apis/codegen.manifest.ts +++ b/packages/data-apis/codegen.manifest.ts @@ -20,6 +20,28 @@ export default { }, ], }, + { + spec: "prices", + schemaTypeName: "PricesRestSchema", + // Spec paths: /{apiKey}/tokens/by-symbol etc. Runtime auth is + // header-based against https://api.g.alchemy.com/prices/v1. + pathRules: { stripApiKeySegment: true }, + operations: [ + { + operationId: "get-token-prices-by-symbol", + exportBaseName: "GetTokenPricesBySymbol", + emitQueryType: true, + }, + { + operationId: "get-token-prices-by-address", + exportBaseName: "GetTokenPricesByAddress", + }, + { + operationId: "get-historical-token-prices", + exportBaseName: "GetHistoricalTokenPrices", + }, + ], + }, { spec: "nft", schemaTypeName: "NftRestSchema", @@ -46,5 +68,23 @@ export default { }, ], }, + { + spec: "token", + schemaTypeName: "TokenRpcSchema", + methods: [ + { + method: "alchemy_getTokenBalances", + exportBaseName: "AlchemyGetTokenBalances", + }, + { + method: "alchemy_getTokenMetadata", + exportBaseName: "AlchemyGetTokenMetadata", + }, + { + method: "alchemy_getTokenAllowance", + exportBaseName: "AlchemyGetTokenAllowance", + }, + ], + }, ], } satisfies CodegenManifest; diff --git a/packages/data-apis/src/generated/rest/portfolio.types.ts b/packages/data-apis/src/generated/rest/portfolio.types.ts index 5cacfec454..b0adf078e7 100644 --- a/packages/data-apis/src/generated/rest/portfolio.types.ts +++ b/packages/data-apis/src/generated/rest/portfolio.types.ts @@ -163,7 +163,7 @@ export interface components { */ includeNativeTokens: boolean; /** - * @description Boolean - if set to `true`, returns ERC-20 tokens. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`. + * @description Boolean - if set to `true`, returns ERC-20 tokens. Setting this to false will reduce payload size and may result in a faster API call. * @default true */ includeErc20Tokens: boolean; @@ -188,12 +188,12 @@ export interface components { networks: string[]; }[]; /** - * @description Boolean - if set to `true`, returns metadata. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`. + * @description Boolean - if set to `true`, returns metadata. Setting this to false will reduce payload size and may result in a faster API call. * @default true */ withMetadata: boolean; /** - * @description Boolean - if set to `true`, returns token prices. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`. + * @description Boolean - if set to `true`, returns token prices. Setting this to false will reduce payload size and may result in a faster API call. * @default true */ withPrices: boolean; @@ -204,7 +204,7 @@ export interface components { */ includeNativeTokens: boolean; /** - * @description Boolean - if set to `true`, returns ERC-20 tokens. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`. + * @description Boolean - if set to `true`, returns ERC-20 tokens. Setting this to false will reduce payload size and may result in a faster API call. * @default true */ includeErc20Tokens: boolean; @@ -267,7 +267,7 @@ export interface components { spamConfidenceLevel?: "VERY_HIGH" | "HIGH" | "MEDIUM" | "LOW"; }[]; /** - * @description Boolean - if set to `true`, returns metadata. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`. + * @description Boolean - if set to `true`, returns metadata. Setting this to false will reduce payload size and may result in a faster API call. * @default true */ withMetadata: boolean; @@ -295,7 +295,7 @@ export interface components { networks: string[]; }[]; /** - * @description Boolean - if set to `true`, returns metadata. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`. + * @description Boolean - if set to `true`, returns metadata. Setting this to false will reduce payload size and may result in a faster API call. * @default true */ withMetadata: boolean; @@ -1038,12 +1038,12 @@ export interface operations { networks: string[]; }[]; /** - * @description Boolean - if set to `true`, returns metadata. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`. + * @description Boolean - if set to `true`, returns metadata. Setting this to false will reduce payload size and may result in a faster API call. * @default true */ withMetadata?: boolean; /** - * @description Boolean - if set to `true`, returns token prices. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`. + * @description Boolean - if set to `true`, returns token prices. Setting this to false will reduce payload size and may result in a faster API call. * @default true */ withPrices?: boolean; @@ -1054,7 +1054,7 @@ export interface operations { */ includeNativeTokens?: boolean; /** - * @description Boolean - if set to `true`, returns ERC-20 tokens. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`. + * @description Boolean - if set to `true`, returns ERC-20 tokens. Setting this to false will reduce payload size and may result in a faster API call. * @default true */ includeErc20Tokens?: boolean; @@ -1195,7 +1195,7 @@ export interface operations { */ includeNativeTokens?: boolean; /** - * @description Boolean - if set to `true`, returns ERC-20 tokens. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`. + * @description Boolean - if set to `true`, returns ERC-20 tokens. Setting this to false will reduce payload size and may result in a faster API call. * @default true */ includeErc20Tokens?: boolean; @@ -1328,7 +1328,7 @@ export interface operations { spamConfidenceLevel?: "VERY_HIGH" | "HIGH" | "MEDIUM" | "LOW"; }[]; /** - * @description Boolean - if set to `true`, returns metadata. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`. + * @description Boolean - if set to `true`, returns metadata. Setting this to false will reduce payload size and may result in a faster API call. * @default true */ withMetadata?: boolean; @@ -1589,7 +1589,7 @@ export interface operations { spamConfidenceLevel?: "VERY_HIGH" | "HIGH" | "MEDIUM" | "LOW"; }[]; /** - * @description Boolean - if set to `true`, returns metadata. Setting this to false will reduce payload size and may result in a faster API call. Defaults to `true`. + * @description Boolean - if set to `true`, returns metadata. Setting this to false will reduce payload size and may result in a faster API call. * @default true */ withMetadata?: boolean; diff --git a/packages/data-apis/src/generated/rest/prices.schema.ts b/packages/data-apis/src/generated/rest/prices.schema.ts new file mode 100644 index 0000000000..556f6cca20 --- /dev/null +++ b/packages/data-apis/src/generated/rest/prices.schema.ts @@ -0,0 +1,68 @@ +/* eslint-disable -- machine-generated file */ +// AUTO-GENERATED by @alchemy/api-codegen — DO NOT EDIT. +// Regenerate with `pnpm generate`. Spec provenance (docs repo commit + checksums) +// is recorded in packages/api-codegen/specs/specs.lock.json. + +import type { RestRequestSchema } from "@alchemy/common"; +import type { operations } from "./prices.types.js"; + +/** 200 response for get-token-prices-by-symbol. */ +export type GetTokenPricesBySymbolResponse = + operations["get-token-prices-by-symbol"]["responses"]["200"]["content"]["application/json"]; + +/** + * Query params for get-token-prices-by-symbol. Sent via the URL at runtime; + * RestRequestSchema has no query channel, so this is exposed as a + * standalone type for the SDK's params layer. + */ +export type GetTokenPricesBySymbolQuery = NonNullable< + operations["get-token-prices-by-symbol"]["parameters"]["query"] +>; + +/** Request body for get-token-prices-by-address. */ +export type GetTokenPricesByAddressBody = NonNullable< + operations["get-token-prices-by-address"]["requestBody"] +>["content"]["application/json"]; + +/** 200 response for get-token-prices-by-address. */ +export type GetTokenPricesByAddressResponse = + operations["get-token-prices-by-address"]["responses"]["200"]["content"]["application/json"]; + +/** Request body for get-historical-token-prices. */ +export type GetHistoricalTokenPricesBody = NonNullable< + operations["get-historical-token-prices"]["requestBody"] +>["content"]["application/json"]; + +/** 200 response for get-historical-token-prices. */ +export type GetHistoricalTokenPricesResponse = + operations["get-historical-token-prices"]["responses"]["200"]["content"]["application/json"]; + +/** RestRequestSchema entries for the prices REST API. */ +export type PricesRestSchema = readonly [ + { + /** GET /{apiKey}/tokens/by-symbol (operationId: get-token-prices-by-symbol) */ + Route: "tokens/by-symbol"; + Method: "GET"; + Body?: undefined; + Response: GetTokenPricesBySymbolResponse; + }, + { + /** POST /{apiKey}/tokens/by-address (operationId: get-token-prices-by-address) */ + Route: "tokens/by-address"; + Method: "POST"; + Body: GetTokenPricesByAddressBody; + Response: GetTokenPricesByAddressResponse; + }, + { + /** POST /{apiKey}/tokens/historical (operationId: get-historical-token-prices) */ + Route: "tokens/historical"; + Method: "POST"; + Body: GetHistoricalTokenPricesBody; + Response: GetHistoricalTokenPricesResponse; + }, +]; + +/** Compile-time guard that the emitted tuple satisfies the shared constraint. */ +export type _AssertPricesRestSchema = PricesRestSchema extends RestRequestSchema + ? true + : never; diff --git a/packages/data-apis/src/generated/rest/prices.types.ts b/packages/data-apis/src/generated/rest/prices.types.ts new file mode 100644 index 0000000000..8afa73c9f2 --- /dev/null +++ b/packages/data-apis/src/generated/rest/prices.types.ts @@ -0,0 +1,735 @@ +/* eslint-disable -- machine-generated file */ +// AUTO-GENERATED by @alchemy/api-codegen — DO NOT EDIT. +// Regenerate with `pnpm generate`. Spec provenance (docs repo commit + checksums) +// is recorded in packages/api-codegen/specs/specs.lock.json. + +export interface paths { + "/{apiKey}/tokens/by-symbol": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Token Prices By Symbol + * @description Fetches current prices for multiple tokens using their symbols. Returns a list of token prices, each containing the symbol, prices, and an optional error field. + */ + get: operations["get-token-prices-by-symbol"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/{apiKey}/tokens/by-address": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Token Prices By Address + * @description Fetches current prices for multiple tokens using network and address pairs. Returns a list of token prices, each containing the network, address, prices, and an optional error field. + */ + post: operations["get-token-prices-by-address"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/{apiKey}/tokens/historical": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Historical Token Prices + * @description Provides historical price data for a single token over a time range. You can identify the token by symbol or by network and contract address. + */ + post: operations["get-historical-token-prices"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; +} +export type webhooks = Record; +export interface components { + schemas: { + TokenPricesResponse: { + /** @description List of token price data. */ + data: { + /** @description Token symbol. */ + symbol: string; + /** @description List of price information. */ + prices: { + /** @description Currency code (e.g., USD). */ + currency: string; + /** @description Price value as a string. */ + value: string; + /** + * Format: date-time + * @description Time when the price was last updated. + */ + lastUpdatedAt: string; + }[]; + /** @description Error message if applicable. */ + error: string; + }[]; + }; + TokenPriceResponseItem: { + /** @description Token symbol. */ + symbol: string; + /** @description List of price information. */ + prices: { + /** @description Currency code (e.g., USD). */ + currency: string; + /** @description Price value as a string. */ + value: string; + /** + * Format: date-time + * @description Time when the price was last updated. + */ + lastUpdatedAt: string; + }[]; + /** @description Error message if applicable. */ + error: string; + }; + ByAddressRequest: { + /** @description Array of token network and address pairs (limit 25 addresses, max 3 networks). Networks should match network enums. */ + addresses: { + /** + * @description Network identifier (e.g., eth-mainnet). Find more network enums [here](https://dashboard.alchemy.com/chains) + * @default eth-mainnet + * @example eth-mainnet + */ + network: string; + /** + * @description Token contract address. + * @default 0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48 + * @example 0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48 + */ + address: string; + }[]; + }; + AddressPricesResponse: { + /** @description List of token prices by address. */ + data: { + /** @description Network identifier. */ + network: string; + /** @description Token contract address. */ + address: string; + /** @description List of price information. */ + prices: { + /** @description Currency code (e.g., USD). */ + currency: string; + /** @description Price value as a string. */ + value: string; + /** + * Format: date-time + * @description Time when the price was last updated. + */ + lastUpdatedAt: string; + }[]; + /** @description Error message if applicable. */ + error: string; + }[]; + }; + AddressPriceResponseItem: { + /** @description Network identifier. */ + network: string; + /** @description Token contract address. */ + address: string; + /** @description List of price information. */ + prices: { + /** @description Currency code (e.g., USD). */ + currency: string; + /** @description Price value as a string. */ + value: string; + /** + * Format: date-time + * @description Time when the price was last updated. + */ + lastUpdatedAt: string; + }[]; + /** @description Error message if applicable. */ + error: string; + }; + /** @description Response containing historical price data. It will either include `symbol` or both `network` and `address` based on the request. */ + HistoricalPricesResponse: + | { + /** + * @description Token symbol. + * @default ETH + * @example ETH + */ + symbol: string; + /** + * @description Currency identifier. + * @default usd + * @example usd + */ + currency: string; + /** @description List of historical price data points. */ + data: { + /** + * @description Price value as a string. + * @example 1900.00 + */ + value: string; + /** + * Format: date-time + * @description Timestamp of the price data point. + * @example 2024-01-01T00:00:00Z + */ + timestamp: string; + /** + * @description Total market capitalization at the timestamp + * @example 274292310008.21802 + */ + marketCap?: string; + /** + * @description Volume traded during the defined interval + * @example 6715146404.608721 + */ + totalVolume?: string; + }[]; + } + | { + /** + * @description Network identifier. + * @default eth-mainnet + * @example eth-mainnet + */ + network: string; + /** + * @description Token contract address. + * @default 0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48 + * @example 0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48 + */ + address: string; + /** + * @description Currency identifier. + * @default usd + * @example usd + */ + currency: string; + /** @description List of historical price data points. */ + data: { + /** + * @description Price value as a string. + * @example 1900.00 + */ + value: string; + /** + * Format: date-time + * @description Timestamp of the price data point. + * @example 2024-01-01T00:00:00Z + */ + timestamp: string; + /** + * @description Total market capitalization at the timestamp + * @example 274292310008.21802 + */ + marketCap?: string; + /** + * @description Volume traded during the defined interval + * @example 6715146404.608721 + */ + totalVolume?: string; + }[]; + }; + HistoricalPricesBySymbol: { + /** + * @description Token symbol. + * @default ETH + * @example ETH + */ + symbol: string; + /** + * @description Currency identifier. + * @default usd + * @example usd + */ + currency: string; + /** @description List of historical price data points. */ + data: { + /** + * @description Price value as a string. + * @example 1900.00 + */ + value: string; + /** + * Format: date-time + * @description Timestamp of the price data point. + * @example 2024-01-01T00:00:00Z + */ + timestamp: string; + /** + * @description Total market capitalization at the timestamp + * @example 274292310008.21802 + */ + marketCap?: string; + /** + * @description Volume traded during the defined interval + * @example 6715146404.608721 + */ + totalVolume?: string; + }[]; + }; + HistoricalPricesByAddress: { + /** + * @description Network identifier. + * @default eth-mainnet + * @example eth-mainnet + */ + network: string; + /** + * @description Token contract address. + * @default 0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48 + * @example 0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48 + */ + address: string; + /** + * @description Currency identifier. + * @default usd + * @example usd + */ + currency: string; + /** @description List of historical price data points. */ + data: { + /** + * @description Price value as a string. + * @example 1900.00 + */ + value: string; + /** + * Format: date-time + * @description Timestamp of the price data point. + * @example 2024-01-01T00:00:00Z + */ + timestamp: string; + /** + * @description Total market capitalization at the timestamp + * @example 274292310008.21802 + */ + marketCap?: string; + /** + * @description Volume traded during the defined interval + * @example 6715146404.608721 + */ + totalVolume?: string; + }[]; + }; + }; + responses: never; + parameters: never; + requestBodies: never; + headers: never; + pathItems: never; +} +export type $defs = Record; +export interface operations { + "get-token-prices-by-symbol": { + parameters: { + query: { + /** @description Array of token symbols (limit 25). Example: symbols=[ETH,BTC] */ + symbols: string[]; + }; + header?: never; + path: { + apiKey: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Successful response, even if some tokens are missing. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description List of token price data. */ + data: { + /** @description Token symbol. */ + symbol: string; + /** @description List of price information. */ + prices: { + /** @description Currency code (e.g., USD). */ + currency: string; + /** @description Price value as a string. */ + value: string; + /** + * Format: date-time + * @description Time when the price was last updated. + */ + lastUpdatedAt: string; + }[]; + /** @description Error message if applicable. */ + error: string; + }[]; + }; + }; + }; + /** @description Bad Request: Malformed request or missing parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description Error details. */ + error: { + /** @description Detailed error message. */ + message: string; + }; + }; + }; + }; + /** @description Too Many Requests: Rate limit exceeded. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description Error details. */ + error: { + /** @description Detailed error message. */ + message: string; + }; + }; + }; + }; + }; + }; + "get-token-prices-by-address": { + parameters: { + query?: never; + header?: never; + path: { + apiKey: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": { + /** @description Array of token network and address pairs (limit 25 addresses, max 3 networks). Networks should match network enums. */ + addresses: { + /** + * @description Network identifier (e.g., eth-mainnet). Find more network enums [here](https://dashboard.alchemy.com/chains) + * @default eth-mainnet + * @example eth-mainnet + */ + network: string; + /** + * @description Token contract address. + * @default 0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48 + * @example 0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48 + */ + address: string; + }[]; + }; + }; + }; + responses: { + /** @description Successful response, even if some prices are missing. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description List of token prices by address. */ + data: { + /** @description Network identifier. */ + network: string; + /** @description Token contract address. */ + address: string; + /** @description List of price information. */ + prices: { + /** @description Currency code (e.g., USD). */ + currency: string; + /** @description Price value as a string. */ + value: string; + /** + * Format: date-time + * @description Time when the price was last updated. + */ + lastUpdatedAt: string; + }[]; + /** @description Error message if applicable. */ + error: string; + }[]; + }; + }; + }; + /** @description Bad Request: Invalid input (e.g., malformed JSON). */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description Error details. */ + error: { + /** @description Detailed error message. */ + message: string; + }; + }; + }; + }; + /** @description Too Many Requests: Rate limit exceeded. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description Error details. */ + error: { + /** @description Detailed error message. */ + message: string; + }; + }; + }; + }; + }; + }; + "get-historical-token-prices": { + parameters: { + query?: never; + header?: never; + path: { + apiKey: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": + | { + /** + * @description Token symbol (e.g., ETH, BTC). + * @default ETH + * @example ETH + */ + symbol: string; + /** + * @description Start of the time range. + * @example 2024-01-01T00:00:00Z + */ + startTime: string | number; + /** + * @description End of the time range. + * @example 2024-01-31T23:59:59Z + */ + endTime: string | number; + /** + * @description Time interval for data points. Max ranges: (5m, 7d), (1h, 30d), (1d, 1yr) + * @default 1d + * @example 1d + * @enum {string} + */ + interval?: "5m" | "1h" | "1d"; + /** + * @description Whether to include market cap and volume for each token + * @default false + * @example true + */ + withMarketData?: boolean; + } + | { + /** + * @description Network identifier (e.g., eth-mainnet). + * @default eth-mainnet + * @example eth-mainnet + */ + network: string; + /** + * @description Token contract address. + * @default 0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48 + * @example 0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48 + */ + address: string; + /** + * @description Start of the time range. + * @example 2024-01-01T00:00:00Z + */ + startTime: string | number; + /** + * @description End of the time range. + * @example 2024-01-31T23:59:59Z + */ + endTime: string | number; + /** + * @description Time interval for data points. Max ranges: (5m, 7d), (1h, 30d), (1d, 1yr) + * @default 1d + * @example 1d + * @enum {string} + */ + interval?: "5m" | "1h" | "1d"; + /** + * @description Whether to include market cap and volume for each token + * @default false + * @example true + */ + withMarketData?: boolean; + }; + }; + }; + responses: { + /** @description Successful response with historical price data. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": + | { + /** + * @description Token symbol. + * @default ETH + * @example ETH + */ + symbol: string; + /** + * @description Currency identifier. + * @default usd + * @example usd + */ + currency: string; + /** @description List of historical price data points. */ + data: { + /** + * @description Price value as a string. + * @example 1900.00 + */ + value: string; + /** + * Format: date-time + * @description Timestamp of the price data point. + * @example 2024-01-01T00:00:00Z + */ + timestamp: string; + /** + * @description Total market capitalization at the timestamp + * @example 274292310008.21802 + */ + marketCap?: string; + /** + * @description Volume traded during the defined interval + * @example 6715146404.608721 + */ + totalVolume?: string; + }[]; + } + | { + /** + * @description Network identifier. + * @default eth-mainnet + * @example eth-mainnet + */ + network: string; + /** + * @description Token contract address. + * @default 0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48 + * @example 0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48 + */ + address: string; + /** + * @description Currency identifier. + * @default usd + * @example usd + */ + currency: string; + /** @description List of historical price data points. */ + data: { + /** + * @description Price value as a string. + * @example 1900.00 + */ + value: string; + /** + * Format: date-time + * @description Timestamp of the price data point. + * @example 2024-01-01T00:00:00Z + */ + timestamp: string; + /** + * @description Total market capitalization at the timestamp + * @example 274292310008.21802 + */ + marketCap?: string; + /** + * @description Volume traded during the defined interval + * @example 6715146404.608721 + */ + totalVolume?: string; + }[]; + }; + }; + }; + /** @description Bad Request: Invalid input (e.g., malformed request, missing parameters). */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description Error details. */ + error: { + /** @description Detailed error message. */ + message: string; + }; + }; + }; + }; + /** @description Not Found: Token not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description Error details. */ + error: { + /** @description Detailed error message. */ + message: string; + }; + }; + }; + }; + /** @description Too Many Requests: Rate limit exceeded. */ + 429: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description Error details. */ + error: { + /** @description Detailed error message. */ + message: string; + }; + }; + }; + }; + }; + }; +} diff --git a/packages/data-apis/src/generated/rpc/token.ts b/packages/data-apis/src/generated/rpc/token.ts new file mode 100644 index 0000000000..036e4dcde4 --- /dev/null +++ b/packages/data-apis/src/generated/rpc/token.ts @@ -0,0 +1,105 @@ +/* eslint-disable -- machine-generated file */ +// AUTO-GENERATED by @alchemy/api-codegen — DO NOT EDIT. +// Regenerate with `pnpm generate`. Spec provenance (docs repo commit + checksums) +// is recorded in packages/api-codegen/specs/specs.lock.json. + +export type AlchemyGetTokenBalancesAddressParam = string; + +export type AlchemyGetTokenBalancesTokenSpecParam = + | ("erc20" | "DEFAULT_TOKENS" | "NATIVE_TOKEN") + | string[]; + +export interface AlchemyGetTokenBalancesOptionsParam { + /** + * Used for pagination if more results are available. + */ + pageKey?: string; + /** + * Maximum number of token balances to return per call (capped at 100). + */ + maxCount?: number; +} + +export interface AlchemyGetTokenBalancesResult { + /** + * Address for which token balances were returned. + */ + address?: string; + /** + * Array of token balance objects. Exactly one of tokenBalance or error is non-null. + */ + tokenBalances?: { + /** + * The ERC-20 contract address. + */ + contractAddress?: string; + /** + * Hex-encoded string of the token balance, or null if error is present. + */ + tokenBalance?: string; + }[]; +} + +export type AlchemyGetTokenMetadataParams = string; + +export interface AlchemyGetTokenMetadataResult { + /** + * Token's name, or null if not found. + */ + name?: string; + /** + * Token's symbol, or null if not found. + */ + symbol?: string; + /** + * Number of decimals the token uses, or null if not found. + */ + decimals?: number; + /** + * URL of the token's logo image, or null if none available. + */ + logo?: string; +} + +export interface AlchemyGetTokenAllowanceParams { + /** + * 20-byte token contract address. + */ + contract: string; + /** + * 20-byte address of the owner. + */ + owner: string; + /** + * 20-byte address of the spender. + */ + spender: string; +} + +/** + * A decimal string representing the allowance. + */ +export type AlchemyGetTokenAllowanceResult = string; + +/** viem RpcSchema entries for the token JSON-RPC methods. */ +export type TokenRpcSchema = [ + { + Method: "alchemy_getTokenBalances"; + Parameters: [ + address: AlchemyGetTokenBalancesAddressParam, + tokenSpec?: AlchemyGetTokenBalancesTokenSpecParam, + options?: AlchemyGetTokenBalancesOptionsParam, + ]; + ReturnType: AlchemyGetTokenBalancesResult; + }, + { + Method: "alchemy_getTokenMetadata"; + Parameters: [contractAddress: AlchemyGetTokenMetadataParams]; + ReturnType: AlchemyGetTokenMetadataResult; + }, + { + Method: "alchemy_getTokenAllowance"; + Parameters: [tokenAllowanceRequest: AlchemyGetTokenAllowanceParams]; + ReturnType: AlchemyGetTokenAllowanceResult; + }, +]; diff --git a/packages/data-apis/src/generated/rpc/transfers.ts b/packages/data-apis/src/generated/rpc/transfers.ts index 9cb54064dc..19b69c30be 100644 --- a/packages/data-apis/src/generated/rpc/transfers.ts +++ b/packages/data-apis/src/generated/rpc/transfers.ts @@ -34,7 +34,7 @@ export interface AlchemyGetAssetTransfersParams { } export type AlchemyGetAssetTransfersResult = - | NotFoundNull + | string | { /** * Uuid of next page of results (if exists, else blank). @@ -113,7 +113,6 @@ export type AlchemyGetAssetTransfersResult = }; }[]; }; -export type NotFoundNull = string; /** viem RpcSchema entries for the transfers JSON-RPC methods. */ export type TransfersRpcSchema = [ From c117d02b7fd24af0668ca94bccf6ce0a2b8840f8 Mon Sep 17 00:00:00 2001 From: blake duncan Date: Wed, 10 Jun 2026 10:25:43 -0400 Subject: [PATCH 2/8] feat(common): harden AlchemyRestClient (query, retries, timeout, request-id) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - RestRequestSchema gains an optional Query channel; RestRequestParams maps it via a keyof guard so legacy entries without Query keep compiling and reject query payloads. Route-literal Response narrowing unchanged. - Bounded retries with exponential backoff on 429/5xx/network failures only, honoring Retry-After; per-attempt AbortSignal.timeout merged with the caller's signal (caller aborts are never retried); per-request UUID sent as X-Alchemy-Client-Request-Id on every attempt. - New AlchemyApiError base (status/code/requestId/retryAfter) under BaseError; ServerError/FetchError re-parented onto it with an additive trailing details param — existing instanceof checks and constructor calls are unaffected. - composeSignals/sleep utils; 11 new rest client tests (query serialization, retry/backoff/Retry-After, abort, request-id propagation, error fields). Co-Authored-By: Claude Fable 5 --- packages/common/src/errors/AlchemyApiError.ts | 72 +++++++ packages/common/src/errors/FetchError.ts | 18 +- packages/common/src/errors/ServerError.ts | 19 +- packages/common/src/index.ts | 3 + packages/common/src/rest/restClient.ts | 172 ++++++++++++++-- packages/common/src/rest/types.ts | 40 +++- packages/common/src/utils/signals.ts | 55 +++++ packages/common/tests/rest/restClient.test.ts | 191 ++++++++++++++++++ 8 files changed, 543 insertions(+), 27 deletions(-) create mode 100644 packages/common/src/errors/AlchemyApiError.ts create mode 100644 packages/common/src/utils/signals.ts create mode 100644 packages/common/tests/rest/restClient.test.ts diff --git a/packages/common/src/errors/AlchemyApiError.ts b/packages/common/src/errors/AlchemyApiError.ts new file mode 100644 index 0000000000..006ca134e1 --- /dev/null +++ b/packages/common/src/errors/AlchemyApiError.ts @@ -0,0 +1,72 @@ +import { BaseError } from "./BaseError.js"; + +/** Normalized failure metadata shared across REST and JSON-RPC channels. */ +export type AlchemyApiErrorDetails = { + /** HTTP status code, when the failure was an HTTP response. */ + status?: number; + /** Provider error code: JSON-RPC `error.code` or a REST error-body code. */ + code?: number | string; + /** The client-generated X-Alchemy-Client-Request-Id sent with the request. */ + requestId?: string; + /** Parsed Retry-After hint in milliseconds, when the server provided one. */ + retryAfter?: number; +}; + +/** + * The normalized error family for Alchemy API failures. Both the REST channel + * (AlchemyRestClient → ServerError/FetchError, which extend this class) and + * SDK JSON-RPC actions surface failures as AlchemyApiError, so consumers can + * handle status/code/requestId/retryAfter uniformly: + * + * ```ts + * try { ... } catch (e) { + * if (e instanceof AlchemyApiError && e.status === 429) { + * await sleep(e.retryAfter ?? 1_000); + * } + * } + * ``` + */ +export class AlchemyApiError extends BaseError { + override name = "AlchemyApiError"; + + /** HTTP status code, when the failure was an HTTP response. */ + readonly status?: number; + /** Provider error code: JSON-RPC `error.code` or a REST error-body code. */ + readonly code?: number | string; + /** The client-generated X-Alchemy-Client-Request-Id sent with the request. */ + readonly requestId?: string; + /** Parsed Retry-After hint in milliseconds, when the server provided one. */ + readonly retryAfter?: number; + + /** + * Creates a normalized API error. + * + * @param {string} shortMessage The headline error message + * @param {AlchemyApiErrorDetails & { cause?: Error; details?: string; metaMessages?: string[] }} [args] Failure metadata plus BaseError options + */ + constructor( + shortMessage: string, + args: AlchemyApiErrorDetails & { + cause?: Error; + details?: string; + metaMessages?: string[]; + } = {}, + ) { + const { status, code, requestId, retryAfter, ...baseArgs } = args; + const metaMessages = [ + ...(baseArgs.metaMessages ?? []), + ...(requestId ? [`Request ID: ${requestId}`] : []), + ]; + // BaseError takes cause XOR details; forward whichever was provided. + super( + shortMessage, + baseArgs.cause + ? { cause: baseArgs.cause, metaMessages } + : { details: baseArgs.details, metaMessages }, + ); + this.status = status; + this.code = code; + this.requestId = requestId; + this.retryAfter = retryAfter; + } +} diff --git a/packages/common/src/errors/FetchError.ts b/packages/common/src/errors/FetchError.ts index e6b014b89e..08b65a55a0 100644 --- a/packages/common/src/errors/FetchError.ts +++ b/packages/common/src/errors/FetchError.ts @@ -1,21 +1,31 @@ -import { BaseError } from "./BaseError.js"; +import { + AlchemyApiError, + type AlchemyApiErrorDetails, +} from "./AlchemyApiError.js"; /** * Error class representing a "Fetch Error" error, typically thrown when a fetch request fails. */ -export class FetchError extends BaseError { +export class FetchError extends AlchemyApiError { override name = "FetchError"; /** - * Initializes a new instance of the error message with a default message indicating that no chain was supplied to the client. + * Initializes a new fetch error for a request that failed before a response. * * @param {string} route - The route that failed to fetch. * @param {string} method - The HTTP method that was used. * @param {Error} cause - The cause of the error. + * @param {AlchemyApiErrorDetails} apiDetails - Normalized failure metadata (requestId). */ - constructor(route: string, method: string, cause?: Error) { + constructor( + route: string, + method: string, + cause?: Error, + apiDetails?: AlchemyApiErrorDetails, + ) { super(`[${method}] ${route} failed to fetch`, { cause, + ...apiDetails, }); } } diff --git a/packages/common/src/errors/ServerError.ts b/packages/common/src/errors/ServerError.ts index 8be8d719c8..575fd792e2 100644 --- a/packages/common/src/errors/ServerError.ts +++ b/packages/common/src/errors/ServerError.ts @@ -1,21 +1,32 @@ -import { BaseError } from "./BaseError.js"; +import { + AlchemyApiError, + type AlchemyApiErrorDetails, +} from "./AlchemyApiError.js"; /** * Error class representing a "Server Error" error, typically thrown when a server request fails. */ -export class ServerError extends BaseError { +export class ServerError extends AlchemyApiError { override name = "ServerError"; /** - * Initializes a new instance of the error message with a default message indicating that no chain was supplied to the client. + * Initializes a new server error for a failed HTTP response. * * @param {string} message - The error message. * @param {number} status - The HTTP status code of the error. * @param {Error} cause - The cause of the error. + * @param {AlchemyApiErrorDetails} apiDetails - Normalized failure metadata (requestId, retryAfter, code). */ - constructor(message: string, status: number, cause?: Error) { + constructor( + message: string, + status: number, + cause?: Error, + apiDetails?: AlchemyApiErrorDetails, + ) { super(`HTTP request failed with status ${status}: ${message}`, { cause, + ...apiDetails, + status, }); } } diff --git a/packages/common/src/index.ts b/packages/common/src/index.ts index 2d927a9751..93516801a0 100644 --- a/packages/common/src/index.ts +++ b/packages/common/src/index.ts @@ -25,6 +25,7 @@ export { resolveNetwork } from "./networks/networkRegistry.js"; // utils export type * from "./utils/types.js"; +export { composeSignals, sleep } from "./utils/signals.js"; export { assertNever } from "./utils/assertNever.js"; export { raise } from "./utils/raise.js"; export { bigIntMultiply, bigIntMax } from "./utils/bigint.js"; @@ -40,6 +41,8 @@ export { // errors export { BaseError } from "./errors/BaseError.js"; +export type { AlchemyApiErrorDetails } from "./errors/AlchemyApiError.js"; +export { AlchemyApiError } from "./errors/AlchemyApiError.js"; export { ChainNotFoundError } from "./errors/ChainNotFoundError.js"; export { AccountNotFoundError } from "./errors/AccountNotFoundError.js"; export { ConnectionConfigError } from "./errors/ConnectionConfigError.js"; diff --git a/packages/common/src/rest/restClient.ts b/packages/common/src/rest/restClient.ts index 014508d651..b8fc3bd4bf 100644 --- a/packages/common/src/rest/restClient.ts +++ b/packages/common/src/rest/restClient.ts @@ -1,10 +1,15 @@ import { FetchError } from "../errors/FetchError.js"; import { ServerError } from "../errors/ServerError.js"; import { withAlchemyHeaders } from "../utils/headers.js"; -import type { RestRequestFn, RestRequestSchema } from "./types.js"; +import { composeSignals, sleep } from "../utils/signals.js"; +import type { QueryParams, RestRequestFn, RestRequestSchema } from "./types.js"; const ALCHEMY_API_URL = "https://api.g.alchemy.com"; +const DEFAULT_RETRY_COUNT = 3; +const DEFAULT_RETRY_DELAY_MS = 150; +const DEFAULT_TIMEOUT_MS = 10_000; + /** * Parameters for creating an AlchemyRestClient instance. */ @@ -17,48 +22,181 @@ export type AlchemyRestClientParams = { url?: string; /** Custom headers to be sent with requests */ headers?: HeadersInit; + /** Max retry attempts after the initial request (default 3; retries 429/5xx/network only) */ + retryCount?: number; + /** Base backoff delay in ms, doubled per attempt (default 150) */ + retryDelay?: number; + /** Per-attempt timeout in ms (default 10000) */ + timeout?: number; }; /** - * A client for making requests to Alchemy's non-JSON-RPC endpoints. + * Serializes a query object to a URL search string. Skips null/undefined + * values; array values append the key repeatedly (wire keys that need the + * bracketed form, e.g. "contractAddresses[]", carry the brackets in the key + * itself). + * + * @param {QueryParams | undefined} query The query object + * @returns {string} A "?key=value..." string, or "" when there is nothing to send + */ +function serializeQuery(query: QueryParams | undefined): string { + if (!query) return ""; + const search = new URLSearchParams(); + for (const [key, value] of Object.entries(query)) { + if (value == null) continue; + if (Array.isArray(value)) { + for (const entry of value) { + if (entry != null) search.append(key, String(entry)); + } + } else { + search.append(key, String(value)); + } + } + const serialized = search.toString(); + return serialized ? `?${serialized}` : ""; +} + +/** + * Parses a Retry-After response header into milliseconds (integer seconds or + * HTTP-date forms). + * + * @param {Response} response The HTTP response + * @returns {number | undefined} Milliseconds to wait, or undefined when absent/unparseable + */ +function parseRetryAfter(response: Response): number | undefined { + const header = response.headers.get("Retry-After"); + if (!header) return undefined; + const seconds = Number(header); + if (Number.isFinite(seconds)) return Math.max(0, seconds * 1000); + const date = Date.parse(header); + if (!Number.isNaN(date)) return Math.max(0, date - Date.now()); + return undefined; +} + +/** + * Best-effort extraction of an error code from a JSON error body. + * + * @param {string} bodyText The raw response body + * @returns {number | string | undefined} The error code, when present + */ +function parseErrorCode(bodyText: string): number | string | undefined { + try { + const parsed = JSON.parse(bodyText); + const code = parsed?.error?.code ?? parsed?.code; + return typeof code === "number" || typeof code === "string" + ? code + : undefined; + } catch { + return undefined; + } +} + +/** + * A client for making requests to Alchemy's non-JSON-RPC endpoints, with + * typed routes/bodies/queries (via a RestRequestSchema), bounded retries with + * exponential backoff (429/5xx/network only, honoring Retry-After), + * per-attempt timeouts, abort support, and a per-request idempotency id sent + * as X-Alchemy-Client-Request-Id and surfaced on thrown errors. */ export class AlchemyRestClient { private readonly url: string; private readonly headers: Headers; + private readonly retryCount: number; + private readonly retryDelay: number; + private readonly timeout: number; /** * Creates a new instance of AlchemyRestClient. * - * @param {AlchemyRestClientParams} params - The parameters for configuring the client, including API key, JWT, custom URL, and headers. + * @param {AlchemyRestClientParams} params - The parameters for configuring the client, including API key, JWT, custom URL, headers, and retry/timeout defaults. */ - constructor({ apiKey, jwt, url, headers }: AlchemyRestClientParams) { + constructor({ + apiKey, + jwt, + url, + headers, + retryCount, + retryDelay, + timeout, + }: AlchemyRestClientParams) { this.url = url ?? ALCHEMY_API_URL; this.headers = new Headers(withAlchemyHeaders({ headers, apiKey, jwt })); + this.retryCount = retryCount ?? DEFAULT_RETRY_COUNT; + this.retryDelay = retryDelay ?? DEFAULT_RETRY_DELAY_MS; + this.timeout = timeout ?? DEFAULT_TIMEOUT_MS; } /** - * Makes an HTTP request to an Alchemy non-JSON-RPC endpoint. + * Makes an HTTP request to an Alchemy non-JSON-RPC endpoint. Retries + * 429/5xx/network failures with exponential backoff (honoring Retry-After); + * other statuses throw immediately. A caller-initiated abort is never + * retried. * * @param {RestRequestFn} params - The parameters for the request * @returns {Promise} The response from the request */ public request: RestRequestFn = async (params) => { - const response = await fetch(`${this.url}/${params.route}`, { - method: params.method, - body: params.body ? JSON.stringify(params.body) : undefined, - headers: this.headers, - }).catch((error) => { - throw new FetchError(params.route, params.method, error); - }); - - if (!response.ok) { + const requestId = crypto.randomUUID(); + const retryCount = params.retryCount ?? this.retryCount; + const retryDelay = params.retryDelay ?? this.retryDelay; + const timeout = params.timeout ?? this.timeout; + + const headers = new Headers(this.headers); + headers.set("X-Alchemy-Client-Request-Id", requestId); + + const url = `${this.url}/${params.route}${serializeQuery( + params.query as QueryParams | undefined, + )}`; + + for (let attempt = 0; ; attempt++) { + // Per-attempt timeout; the caller's signal spans all attempts. + const signal = composeSignals( + params.signal, + AbortSignal.timeout(timeout), + ); + + let response: Response; + try { + response = await fetch(url, { + method: params.method, + body: params.body ? JSON.stringify(params.body) : undefined, + headers, + signal, + }); + } catch (error) { + // A caller-initiated abort propagates as-is, immediately. + if (params.signal?.aborted) throw params.signal.reason; + // Timeout or network failure: retryable. + if (attempt < retryCount) { + await sleep((1 << attempt) * retryDelay, params.signal); + continue; + } + throw new FetchError( + params.route, + params.method, + error instanceof Error ? error : undefined, + { requestId }, + ); + } + + if (response.ok) { + return response.json(); + } + + const retryAfter = parseRetryAfter(response); + const retryable = response.status === 429 || response.status >= 500; + if (retryable && attempt < retryCount) { + await sleep(retryAfter ?? (1 << attempt) * retryDelay, params.signal); + continue; + } + + const bodyText = await response.text(); throw new ServerError( - await response.text(), + bodyText, response.status, new Error(response.statusText), + { requestId, retryAfter, code: parseErrorCode(bodyText) }, ); } - - return response.json(); }; } diff --git a/packages/common/src/rest/types.ts b/packages/common/src/rest/types.ts index ebd6ca6c8c..5520e0d36a 100644 --- a/packages/common/src/rest/types.ts +++ b/packages/common/src/rest/types.ts @@ -1,12 +1,39 @@ import type { Prettify } from "viem"; +/** Values the query serializer accepts (null/undefined entries are skipped). */ +export type QueryValue = string | number | boolean | null | undefined; + +/** A query-params object; array values serialize as repeated keys. */ +export type QueryParams = Record; + export type RestRequestSchema = readonly { Route: string; Method: "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "OPTIONS" | "HEAD"; Body?: unknown | undefined; + Query?: unknown | undefined; Response: unknown; }[]; +/** Per-request runtime options; values override the client-level defaults. */ +export type RestRequestOptions = { + /** Abort the request (and any pending retries). */ + signal?: AbortSignal; + /** Max retry attempts after the initial request (client default applies when omitted). */ + retryCount?: number; + /** Base backoff delay in ms (client default applies when omitted). */ + retryDelay?: number; + /** Per-attempt timeout in ms (client default applies when omitted). */ + timeout?: number; +}; + +/** + * Reads a schema entry's Query member without indexed access, so legacy + * entries that never declared Query resolve to undefined instead of erroring. + */ +type EntryQuery = "Query" extends keyof Entry + ? Entry["Query"] + : undefined; + export type RestRequestParams< Schema extends RestRequestSchema | undefined = undefined, > = Schema extends RestRequestSchema @@ -21,14 +48,23 @@ export type RestRequestParams< ? Schema[K]["Body"] extends undefined ? { body?: undefined } : { body: Schema[K]["Body"] } - : never) + : never) & + (Schema[K] extends Schema[number] + ? EntryQuery extends undefined + ? { query?: undefined } + : undefined extends EntryQuery + ? { query?: EntryQuery } + : { query: EntryQuery } + : never) & + RestRequestOptions >; }[number] : { route: string; method: RestRequestSchema[number]["Method"]; body?: unknown | undefined; - }; + query?: QueryParams | undefined; + } & RestRequestOptions; export type RestRequestFn< Schema extends RestRequestSchema | undefined = undefined, diff --git a/packages/common/src/utils/signals.ts b/packages/common/src/utils/signals.ts new file mode 100644 index 0000000000..e6bd7cfbdb --- /dev/null +++ b/packages/common/src/utils/signals.ts @@ -0,0 +1,55 @@ +/** + * Combines multiple abort signals into one that aborts when any input aborts. + * Uses AbortSignal.any where available, with an addEventListener fallback. + * + * @param {...(AbortSignal | undefined)} signals Signals to combine (undefined entries are skipped) + * @returns {AbortSignal | undefined} The combined signal, or undefined if none were provided + */ +export function composeSignals( + ...signals: Array +): AbortSignal | undefined { + const present = signals.filter((s): s is AbortSignal => s != null); + if (present.length === 0) return undefined; + if (present.length === 1) return present[0]; + if (typeof AbortSignal.any === "function") { + return AbortSignal.any(present); + } + const controller = new AbortController(); + for (const signal of present) { + if (signal.aborted) { + controller.abort(signal.reason); + break; + } + signal.addEventListener("abort", () => controller.abort(signal.reason), { + once: true, + signal: controller.signal, + }); + } + return controller.signal; +} + +/** + * Waits for a duration, rejecting immediately with the signal's reason if the + * signal aborts first. + * + * @param {number} ms Milliseconds to wait + * @param {AbortSignal} [signal] Optional abort signal + * @returns {Promise} Resolves after the delay + */ +export function sleep(ms: number, signal?: AbortSignal): Promise { + return new Promise((resolve, reject) => { + if (signal?.aborted) { + reject(signal.reason); + return; + } + const timer = setTimeout(() => { + signal?.removeEventListener("abort", onAbort); + resolve(); + }, ms); + const onAbort = () => { + clearTimeout(timer); + reject(signal?.reason); + }; + signal?.addEventListener("abort", onAbort, { once: true }); + }); +} diff --git a/packages/common/tests/rest/restClient.test.ts b/packages/common/tests/rest/restClient.test.ts new file mode 100644 index 0000000000..ec8d503882 --- /dev/null +++ b/packages/common/tests/rest/restClient.test.ts @@ -0,0 +1,191 @@ +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; +import { AlchemyRestClient } from "../../src/rest/restClient.js"; +import { AlchemyApiError } from "../../src/errors/AlchemyApiError.js"; +import { ServerError } from "../../src/errors/ServerError.js"; +import { FetchError } from "../../src/errors/FetchError.js"; + +type TestSchema = readonly [ + { + Route: "things"; + Method: "GET"; + Body?: undefined; + Query?: { owner?: string; "tags[]"?: string[]; limit?: number } | undefined; + Response: { ok: boolean }; + }, + { + Route: "things/create"; + Method: "POST"; + Body: { name: string }; + Response: { id: string }; + }, +]; + +const fetchMock = vi.fn(); + +const jsonResponse = (body: unknown, init?: ResponseInit) => + new Response(JSON.stringify(body), { + status: 200, + headers: { "Content-Type": "application/json" }, + ...init, + }); + +const makeClient = ( + overrides?: ConstructorParameters[0], +) => + new AlchemyRestClient({ + apiKey: "test-key", + url: "https://example.test/api", + retryDelay: 1, // keep retry tests fast + ...overrides, + }); + +beforeEach(() => { + vi.stubGlobal("fetch", fetchMock); + fetchMock.mockReset(); +}); + +afterEach(() => { + vi.unstubAllGlobals(); +}); + +describe("AlchemyRestClient query serialization", () => { + it("serializes scalars, repeats array keys, and skips nullish values", async () => { + fetchMock.mockImplementation(async () => jsonResponse({ ok: true })); + const client = makeClient(); + await client.request({ + route: "things", + method: "GET", + query: { owner: "0xabc", "tags[]": ["a", "b"], limit: undefined }, + }); + const url = String(fetchMock.mock.calls[0]![0]); + expect(url).toBe( + "https://example.test/api/things?owner=0xabc&tags%5B%5D=a&tags%5B%5D=b", + ); + }); + + it("sends no query string when the query object is empty", async () => { + fetchMock.mockImplementation(async () => jsonResponse({ ok: true })); + await makeClient().request({ route: "things", method: "GET", query: {} }); + expect(String(fetchMock.mock.calls[0]![0])).toBe( + "https://example.test/api/things", + ); + }); +}); + +describe("AlchemyRestClient request id", () => { + it("sends X-Alchemy-Client-Request-Id and keeps it stable across retries", async () => { + fetchMock + .mockImplementationOnce(async () => jsonResponse({}, { status: 500 })) + .mockImplementationOnce(async () => jsonResponse({ ok: true })); + await makeClient().request({ route: "things", method: "GET" }); + + const ids = fetchMock.mock.calls.map((call) => + (call[1].headers as Headers).get("X-Alchemy-Client-Request-Id"), + ); + expect(ids[0]).toMatch(/^[0-9a-f-]{36}$/); + expect(ids[1]).toBe(ids[0]); + }); + + it("surfaces the request id on thrown ServerError", async () => { + fetchMock.mockImplementation(async () => jsonResponse({}, { status: 400 })); + const error = await makeClient() + .request({ route: "things", method: "GET" }) + .catch((e) => e); + expect(error).toBeInstanceOf(ServerError); + expect(error).toBeInstanceOf(AlchemyApiError); + expect(error.requestId).toMatch(/^[0-9a-f-]{36}$/); + expect(error.status).toBe(400); + }); +}); + +describe("AlchemyRestClient retries", () => { + it("retries 429 and 5xx up to retryCount, then succeeds", async () => { + fetchMock + .mockImplementationOnce(async () => jsonResponse({}, { status: 429 })) + .mockImplementationOnce(async () => jsonResponse({}, { status: 503 })) + .mockImplementationOnce(async () => jsonResponse({ ok: true })); + const result = await makeClient().request({ + route: "things", + method: "GET", + }); + expect(result).toEqual({ ok: true }); + expect(fetchMock).toHaveBeenCalledTimes(3); + }); + + it("does not retry non-429 4xx", async () => { + fetchMock.mockImplementation(async () => + jsonResponse({ error: { code: "bad-owner" } }, { status: 400 }), + ); + const error = await makeClient() + .request({ route: "things", method: "GET" }) + .catch((e) => e); + expect(fetchMock).toHaveBeenCalledTimes(1); + expect(error.code).toBe("bad-owner"); + }); + + it("honors Retry-After seconds and exposes retryAfter on the final error", async () => { + fetchMock.mockImplementation( + async () => + new Response("{}", { + status: 429, + headers: { "Retry-After": "0" }, + }), + ); + const error = await makeClient({ retryCount: 1, retryDelay: 1 }) + .request({ route: "things", method: "GET" }) + .catch((e) => e); + expect(fetchMock).toHaveBeenCalledTimes(2); + expect(error.status).toBe(429); + expect(error.retryAfter).toBe(0); + }); + + it("retries network errors and throws FetchError with requestId when exhausted", async () => { + fetchMock.mockImplementation(async () => { + throw new TypeError("fetch failed"); + }); + const error = await makeClient({ retryCount: 2 }) + .request({ route: "things", method: "GET" }) + .catch((e) => e); + expect(fetchMock).toHaveBeenCalledTimes(3); + expect(error).toBeInstanceOf(FetchError); + expect(error.requestId).toMatch(/^[0-9a-f-]{36}$/); + }); + + it("respects per-request retryCount override of 0", async () => { + fetchMock.mockImplementation(async () => jsonResponse({}, { status: 500 })); + await makeClient() + .request({ route: "things", method: "GET", retryCount: 0 }) + .catch(() => {}); + expect(fetchMock).toHaveBeenCalledTimes(1); + }); +}); + +describe("AlchemyRestClient abort", () => { + it("propagates a caller abort immediately without retrying", async () => { + const controller = new AbortController(); + fetchMock.mockImplementation(async (_url, init: RequestInit) => { + controller.abort(new Error("user-cancelled")); + throw (init.signal as AbortSignal).reason; + }); + const error = await makeClient() + .request({ route: "things", method: "GET", signal: controller.signal }) + .catch((e) => e); + expect(fetchMock).toHaveBeenCalledTimes(1); + expect(error.message).toBe("user-cancelled"); + }); +}); + +describe("AlchemyRestClient bodies", () => { + it("posts JSON bodies as before", async () => { + fetchMock.mockImplementation(async () => jsonResponse({ id: "1" })); + const result = await makeClient().request({ + route: "things/create", + method: "POST", + body: { name: "x" }, + }); + expect(result).toEqual({ id: "1" }); + expect(fetchMock.mock.calls[0]![1].body).toBe( + JSON.stringify({ name: "x" }), + ); + }); +}); From 82622c41b297951bcc4e6834269c5ec910f5fea4 Mon Sep 17 00:00:00 2001 From: blake duncan Date: Wed, 10 Jun 2026 10:36:33 -0400 Subject: [PATCH 3/8] feat(api-codegen): emit Query channel, validate pagination, guard deprecated ops MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - REST tuples now carry the Query channel (required when any query param is required); standalone Query alias emitted whenever query params exist. - Manifest gains optional pagination metadata per operation/method (pageParam / responseCursorField / itemsField, dotted paths for nested cursors); validated against snapshots at generate time — drift in cursor fields fails generation. Consumed by hand-written *Pages actions; emits no runtime code. - Referencing a spec-deprecated operation hard-fails generation. - NFT action drops the URLSearchParams route cast: typed query channel + abort signal via the hardened AlchemyRestClient. Actions accept an optional RequestOptions third arg. - Snapshot lockfile labels detached-HEAD checkouts '(detached)'. Co-Authored-By: Claude Fable 5 --- packages/api-codegen/src/manifest.ts | 20 +++- .../api-codegen/src/rest/schemaEmitter.ts | 93 ++++++++++++++++--- packages/api-codegen/src/rpc/rpcEmitter.ts | 44 ++++++++- packages/api-codegen/src/schemaWalk.ts | 55 +++++++++++ packages/api-codegen/src/snapshot.ts | 3 +- packages/api-codegen/tests/rpcEmitter.test.ts | 33 +++++++ .../api-codegen/tests/schemaEmitter.test.ts | 82 ++++++++++++++++ packages/data-apis/codegen.manifest.ts | 11 ++- .../src/actions/nft/getNftsForOwner.ts | 19 ++-- .../src/generated/rest/nft.schema.ts | 7 +- .../src/generated/rest/portfolio.schema.ts | 1 + .../src/generated/rest/prices.schema.ts | 9 +- .../data-apis/src/internal/clientHelpers.ts | 6 ++ 13 files changed, 344 insertions(+), 39 deletions(-) create mode 100644 packages/api-codegen/src/schemaWalk.ts diff --git a/packages/api-codegen/src/manifest.ts b/packages/api-codegen/src/manifest.ts index f4b1f09d09..9b718bae7a 100644 --- a/packages/api-codegen/src/manifest.ts +++ b/packages/api-codegen/src/manifest.ts @@ -9,14 +9,30 @@ export type PathRules = { stripPrefix?: string; }; +/** + * Cursor-pagination metadata for a method. Validated against the spec + * snapshot at generate time; consumed by hand-written `*Pages` companion + * actions (no runtime code is generated from it). + */ +export type PaginationConfig = { + /** Request param carrying the cursor; dotted path for nested params (e.g. "options.pageKey"). */ + pageParam: string; + /** Success-response field carrying the next cursor (e.g. "pageKey"). */ + responseCursorField: string; + /** Success-response field holding the page's items (e.g. "ownedNfts"). */ + itemsField: string; +}; + /** A single OpenAPI operation the target consumes. */ export type RestOperationConfig = { /** operationId as it appears in the spec (e.g. "getNFTsForOwner-v3"). */ operationId: string; /** Base for emitted type names (e.g. "GetNftsForOwner" → GetNftsForOwnerResponse). */ exportBaseName: string; - /** Also emit a named query-params type (GET endpoints; RestRequestSchema has no query channel). */ + /** Also emit a named query-params type (redundant since the Query channel; kept for compatibility). */ emitQueryType?: boolean; + /** Cursor pagination metadata, when the operation paginates. */ + pagination?: PaginationConfig; }; /** One REST spec consumed by the target. */ @@ -35,6 +51,8 @@ export type RpcMethodConfig = { method: string; /** Base for emitted type names (e.g. "AlchemyGetAssetTransfers"). */ exportBaseName: string; + /** Cursor pagination metadata, when the method paginates. */ + pagination?: PaginationConfig; }; /** One OpenRPC spec consumed by the target. */ diff --git a/packages/api-codegen/src/rest/schemaEmitter.ts b/packages/api-codegen/src/rest/schemaEmitter.ts index ffd16f2ecc..d31df2d799 100644 --- a/packages/api-codegen/src/rest/schemaEmitter.ts +++ b/packages/api-codegen/src/rest/schemaEmitter.ts @@ -1,6 +1,7 @@ import { CodegenError } from "../errors.js"; import { normalizePath } from "./normalizePath.js"; -import type { RestSpecConfig } from "../manifest.js"; +import { schemaHasPath } from "../schemaWalk.js"; +import type { PaginationConfig, RestSpecConfig } from "../manifest.js"; const REST_METHODS = [ "get", @@ -14,9 +15,13 @@ const REST_METHODS = [ type SpecOperation = { operationId?: string; - requestBody?: { content?: Record }; - responses?: Record }>; - parameters?: Array<{ in?: string }>; + deprecated?: boolean; + requestBody?: { content?: Record }; + responses?: Record< + string, + { content?: Record } + >; + parameters?: Array<{ in?: string; name?: string }>; }; type LocatedOperation = { @@ -88,6 +93,51 @@ function pickSuccessResponse( return { status, contentType }; } +/** + * Validates a REST operation's declared pagination metadata against the spec: + * the cursor param must exist among query params or body properties, and the + * cursor/items fields must exist in the success response schema. + * + * @param {string} operationId For error messages + * @param {SpecOperation} operation The located spec operation + * @param {PaginationConfig} pagination The manifest's pagination declaration + * @param {object} success The success response key to inspect + * @param {string} success.status The 2xx status code key + * @param {string} success.contentType The response content type key + */ +function validateRestPagination( + operationId: string, + operation: SpecOperation, + pagination: PaginationConfig, + success: { status: string; contentType: string }, +): void { + const bodySchema = + operation.requestBody?.content?.["application/json"]?.schema; + const inQuery = (operation.parameters ?? []).some( + (param) => param.in === "query" && param.name === pagination.pageParam, + ); + const inBody = bodySchema + ? schemaHasPath(bodySchema, pagination.pageParam) + : false; + if (!inQuery && !inBody) { + throw new CodegenError( + `Operation "${operationId}": pagination pageParam "${pagination.pageParam}" not found among query params or body properties.`, + ); + } + + const responseSchema = + operation.responses?.[success.status]?.content?.[success.contentType] + ?.schema; + for (const field of [pagination.responseCursorField, pagination.itemsField]) { + // Dotted paths supported: portfolio responses nest cursors under "data". + if (!schemaHasPath(responseSchema, field)) { + throw new CodegenError( + `Operation "${operationId}": pagination field "${field}" not found in the ${success.status} response schema.`, + ); + } + } +} + /** * Emits the .schema.ts source for a REST spec: named Body/Response * (and optional Query) aliases indexed into the openapi-typescript output, @@ -105,13 +155,33 @@ export function emitRestSchema( const tupleEntries: string[] = []; for (const opConfig of config.operations) { - const { operationId, exportBaseName, emitQueryType } = opConfig; + const { operationId, exportBaseName, pagination } = opConfig; const { path, method, operation } = locateOperation(spec, operationId); + if (operation.deprecated) { + throw new CodegenError( + `Operation "${operationId}" is marked deprecated in the spec. ` + + `Drop it from the manifest, or map the replacement operation instead.`, + ); + } const route = normalizePath(path, config.pathRules); const hasBody = operation.requestBody != null; + const queryParams = (operation.parameters ?? []).filter( + (param) => param.in === "query", + ); + const hasQuery = queryParams.length > 0; + const hasRequiredQuery = queryParams.some( + (param) => (param as { required?: boolean }).required === true, + ); const { status, contentType } = pickSuccessResponse(operation, operationId); const opIndex = JSON.stringify(operationId); + if (pagination) { + validateRestPagination(operationId, operation, pagination, { + status, + contentType, + }); + } + if (hasBody) { const bodyContentType = Object.keys( operation.requestBody?.content ?? {}, @@ -132,13 +202,9 @@ export function emitRestSchema( ` operations[${opIndex}]["responses"][${JSON.stringify(status)}]["content"][${JSON.stringify(contentType)}];`, ); - if (emitQueryType) { + if (hasQuery) { aliasBlocks.push( - `/**\n` + - ` * Query params for ${operationId}. Sent via the URL at runtime;\n` + - ` * RestRequestSchema has no query channel, so this is exposed as a\n` + - ` * standalone type for the SDK's params layer.\n` + - ` */\n` + + `/** Query params for ${operationId}. */\n` + `export type ${exportBaseName}Query = NonNullable<\n` + ` operations[${opIndex}]["parameters"]["query"]\n` + `>;`, @@ -153,6 +219,11 @@ export function emitRestSchema( (hasBody ? ` Body: ${exportBaseName}Body;\n` : ` Body?: undefined;\n`) + + (hasQuery + ? hasRequiredQuery + ? ` Query: ${exportBaseName}Query;\n` + : ` Query?: ${exportBaseName}Query | undefined;\n` + : ` Query?: undefined;\n`) + ` Response: ${exportBaseName}Response;\n` + ` },`, ); diff --git a/packages/api-codegen/src/rpc/rpcEmitter.ts b/packages/api-codegen/src/rpc/rpcEmitter.ts index 6ce21a2540..111065c685 100644 --- a/packages/api-codegen/src/rpc/rpcEmitter.ts +++ b/packages/api-codegen/src/rpc/rpcEmitter.ts @@ -1,6 +1,8 @@ import { compile } from "json-schema-to-typescript"; -import { extractMethod } from "./openrpcWalker.js"; -import type { RpcSpecConfig } from "../manifest.js"; +import { CodegenError } from "../errors.js"; +import { schemaHasPath } from "../schemaWalk.js"; +import { extractMethod, type ExtractedMethod } from "./openrpcWalker.js"; +import type { PaginationConfig, RpcSpecConfig } from "../manifest.js"; /** * Converts a param name to PascalCase for type naming. @@ -12,6 +14,39 @@ function pascal(name: string): string { return name.charAt(0).toUpperCase() + name.slice(1); } +/** + * Validates an RPC method's declared pagination metadata against the spec: + * the cursor param path must resolve within one of the method's params + * (dotted paths traverse nested object params, e.g. "options.pageKey" on + * alchemy_getTokenBalances), and the cursor/items fields must exist in the + * result schema (combinator branches included). + * + * @param {ExtractedMethod} extracted The extracted method schemas + * @param {PaginationConfig} pagination The manifest's pagination declaration + */ +function validateRpcPagination( + extracted: ExtractedMethod, + pagination: PaginationConfig, +): void { + const [head, ...rest] = pagination.pageParam.split("."); + const param = extracted.params.find((p) => p.name === head); + const paramOk = + param != null && + (rest.length === 0 || schemaHasPath(param.schema, rest.join("."))); + if (!paramOk) { + throw new CodegenError( + `Method "${extracted.name}": pagination pageParam "${pagination.pageParam}" not found among the method's params.`, + ); + } + for (const field of [pagination.responseCursorField, pagination.itemsField]) { + if (!schemaHasPath(extracted.result, field)) { + throw new CodegenError( + `Method "${extracted.name}": pagination field "${field}" not found in the result schema.`, + ); + } + } +} + /** * Emits the .ts source for an OpenRPC spec: per-method param/result * types compiled from their JSON Schemas (json-schema-to-typescript), plus a @@ -29,8 +64,11 @@ export async function emitRpcSchema( const tupleEntries: string[] = []; for (const methodConfig of config.methods) { - const { method, exportBaseName } = methodConfig; + const { method, exportBaseName, pagination } = methodConfig; const extracted = extractMethod(spec, method); + if (pagination) { + validateRpcPagination(extracted, pagination); + } // Single-param methods get the plain "Params" name; multi-param // methods are disambiguated by param name. diff --git a/packages/api-codegen/src/schemaWalk.ts b/packages/api-codegen/src/schemaWalk.ts new file mode 100644 index 0000000000..340b7eebaf --- /dev/null +++ b/packages/api-codegen/src/schemaWalk.ts @@ -0,0 +1,55 @@ +/** + * Checks whether a JSON Schema declares a property, looking through + * oneOf/anyOf/allOf combinators (the transfers result, for example, is a + * oneOf whose object branch carries pageKey/transfers). + * + * @param {unknown} schema A JSON Schema node + * @param {string} property The property name to find + * @returns {boolean} true if any (combinator) branch declares the property + */ +export function schemaHasProperty(schema: unknown, property: string): boolean { + if (schema === null || typeof schema !== "object") return false; + const node = schema as Record; + const properties = node.properties as Record | undefined; + if (properties && property in properties) return true; + for (const combinator of ["oneOf", "anyOf", "allOf"] as const) { + const branches = node[combinator]; + if (Array.isArray(branches)) { + if (branches.some((branch) => schemaHasProperty(branch, property))) { + return true; + } + } + } + return false; +} + +/** + * Resolves a dotted property path within a JSON Schema's properties + * (e.g. "options.pageKey" → properties.options.properties.pageKey). + * + * @param {unknown} schema A JSON Schema node + * @param {string} path Dotted property path + * @returns {boolean} true if the full path resolves + */ +export function schemaHasPath(schema: unknown, path: string): boolean { + const [head, ...rest] = path.split("."); + if (!head) return false; + if (schema === null || typeof schema !== "object") return false; + const properties = (schema as Record).properties as + | Record + | undefined; + if (!properties || !(head in properties)) { + // Look through combinators at this level too. + for (const combinator of ["oneOf", "anyOf", "allOf"] as const) { + const branches = (schema as Record)[combinator]; + if (Array.isArray(branches)) { + if (branches.some((branch) => schemaHasPath(branch, path))) { + return true; + } + } + } + return false; + } + if (rest.length === 0) return true; + return schemaHasPath(properties[head], rest.join(".")); +} diff --git a/packages/api-codegen/src/snapshot.ts b/packages/api-codegen/src/snapshot.ts index 01a25842f6..1e34e167a1 100644 --- a/packages/api-codegen/src/snapshot.ts +++ b/packages/api-codegen/src/snapshot.ts @@ -80,7 +80,8 @@ export async function snapshot(options: SnapshotOptions = {}): Promise { ); } const sha = git(docsDir, ["rev-parse", "HEAD"]); - const branch = git(docsDir, ["rev-parse", "--abbrev-ref", "HEAD"]); + const branchName = git(docsDir, ["rev-parse", "--abbrev-ref", "HEAD"]); + const branch = branchName === "HEAD" ? "(detached)" : branchName; const { rest, rpc } = await collectSpecNames(); console.log( diff --git a/packages/api-codegen/tests/rpcEmitter.test.ts b/packages/api-codegen/tests/rpcEmitter.test.ts index 1459b723e0..0c42ef8862 100644 --- a/packages/api-codegen/tests/rpcEmitter.test.ts +++ b/packages/api-codegen/tests/rpcEmitter.test.ts @@ -53,4 +53,37 @@ describe("emitRpcSchema", () => { ); expect(source).toContain("ReturnType: FixtureGetThingsResult;"); }); + + it("validates dotted pagination paths against params and oneOf results", async () => { + const withPagination = (pageParam: string, itemsField: string) => + emitRpcSchema( + { + spec: "rpc.fixture", + schemaTypeName: "FixtureRpcSchema", + methods: [ + { + method: "fixture_getThings", + exportBaseName: "FixtureGetThings", + pagination: { + pageParam, + responseCursorField: "pageKey", + itemsField, + }, + }, + ], + }, + spec, + ); + // pageKey/things live in the object branch of the oneOf result; the + // cursor param is nested under the single object param. + await expect( + withPagination("thingParams.limit", "things"), + ).resolves.toContain("FixtureRpcSchema"); + await expect(withPagination("thingParams.bogus", "things")).rejects.toThrow( + /thingParams.bogus/, + ); + await expect( + withPagination("thingParams.limit", "bogusItems"), + ).rejects.toThrow(/bogusItems/); + }); }); diff --git a/packages/api-codegen/tests/schemaEmitter.test.ts b/packages/api-codegen/tests/schemaEmitter.test.ts index 45d15daa93..411b7a2018 100644 --- a/packages/api-codegen/tests/schemaEmitter.test.ts +++ b/packages/api-codegen/tests/schemaEmitter.test.ts @@ -55,5 +55,87 @@ describe("emitRestSchema", () => { ); expect(source).toContain(`Route: "getBar";`); expect(source).toContain(`Body?: undefined;`); + // owner is a required query param → Query is required in the tuple + expect(source).toContain(`Query: GetBarQuery;`); + }); + + it("emits Query?: undefined for operations without query params", () => { + const source = emitRestSchema( + { + spec: "rest.fixture", + schemaTypeName: "FooRestSchema", + pathRules: { stripApiKeySegment: true }, + operations: [ + { operationId: "create-foo", exportBaseName: "CreateFoo" }, + ], + }, + spec, + ); + expect(source).toContain(`Query?: undefined;`); + expect(source).not.toContain(`CreateFooQuery`); + }); + + it("validates pagination metadata and hard-errors on unknown fields", () => { + const config = (pagination: { + pageParam: string; + responseCursorField: string; + itemsField: string; + }) => ({ + spec: "rest.fixture", + schemaTypeName: "BarRestSchema", + pathRules: { stripApiKeySegment: true, stripPrefix: "/v3" }, + operations: [ + { operationId: "getBar-v3", exportBaseName: "GetBar", pagination }, + ], + }); + // valid: owner is a query param; items is a response property + expect(() => + emitRestSchema( + config({ + pageParam: "owner", + responseCursorField: "items", + itemsField: "items", + }), + spec, + ), + ).not.toThrow(); + // invalid pageParam + expect(() => + emitRestSchema( + config({ + pageParam: "bogusCursor", + responseCursorField: "items", + itemsField: "items", + }), + spec, + ), + ).toThrow(/bogusCursor/); + // invalid response field + expect(() => + emitRestSchema( + config({ + pageParam: "owner", + responseCursorField: "bogusField", + itemsField: "items", + }), + spec, + ), + ).toThrow(/bogusField/); + }); + + it("hard-errors when the manifest references a deprecated operation", () => { + const deprecatedSpec = JSON.parse(JSON.stringify(spec)); + deprecatedSpec.paths["/v3/{apiKey}/getBar"].get.deprecated = true; + expect(() => + emitRestSchema( + { + spec: "rest.fixture", + schemaTypeName: "BarRestSchema", + pathRules: { stripApiKeySegment: true, stripPrefix: "/v3" }, + operations: [{ operationId: "getBar-v3", exportBaseName: "GetBar" }], + }, + deprecatedSpec, + ), + ).toThrow(/deprecated/); }); }); diff --git a/packages/data-apis/codegen.manifest.ts b/packages/data-apis/codegen.manifest.ts index c35720042b..a2b33f5d12 100644 --- a/packages/data-apis/codegen.manifest.ts +++ b/packages/data-apis/codegen.manifest.ts @@ -52,7 +52,11 @@ export default { { operationId: "getNFTsForOwner-v3", exportBaseName: "GetNftsForOwner", - emitQueryType: true, + pagination: { + pageParam: "pageKey", + responseCursorField: "pageKey", + itemsField: "ownedNfts", + }, }, ], }, @@ -65,6 +69,11 @@ export default { { method: "alchemy_getAssetTransfers", exportBaseName: "AlchemyGetAssetTransfers", + pagination: { + pageParam: "assetTransferParams.pageKey", + responseCursorField: "pageKey", + itemsField: "transfers", + }, }, ], }, diff --git a/packages/data-apis/src/actions/nft/getNftsForOwner.ts b/packages/data-apis/src/actions/nft/getNftsForOwner.ts index ad038ba464..b8a9736f92 100644 --- a/packages/data-apis/src/actions/nft/getNftsForOwner.ts +++ b/packages/data-apis/src/actions/nft/getNftsForOwner.ts @@ -3,6 +3,7 @@ import { getRestClient, resolveRequestNetwork, type DataClient, + type RequestOptions, } from "../../internal/clientHelpers.js"; import type { NftRestSchema } from "../../schema/rest.js"; import type { @@ -17,28 +18,22 @@ import type { * * @param {DataClient} client A client configured with an Alchemy transport * @param {GetNftsForOwnerParams} params Owner address, optional network override, and filters + * @param {RequestOptions} [options] Per-request options (abort signal) * @returns {Promise} The owned NFTs and pagination cursor */ export async function getNftsForOwner( client: DataClient, params: GetNftsForOwnerParams, + options?: RequestOptions, ): Promise { - const { network, owner, contractAddresses, ...rest } = params; + const { network, contractAddresses, ...query } = params; const { slug } = resolveRequestNetwork(client, network); - const query = new URLSearchParams({ owner }); - for (const [key, value] of Object.entries(rest)) { - if (value != null) query.set(key, String(value)); - } - for (const address of contractAddresses ?? []) { - query.append("contractAddresses[]", address); - } - const restClient = getRestClient(client, getNftApiUrl(slug)); - // TODO(common-hardening): AlchemyRestClient should take query params - // first-class instead of this cast; tracked in the data SDK plan. return restClient.request({ - route: `getNFTsForOwner?${query.toString()}` as "getNFTsForOwner", + route: "getNFTsForOwner", method: "GET", + query: { ...query, "contractAddresses[]": contractAddresses }, + signal: options?.signal, }); } diff --git a/packages/data-apis/src/generated/rest/nft.schema.ts b/packages/data-apis/src/generated/rest/nft.schema.ts index c543c83c66..c52bf3c614 100644 --- a/packages/data-apis/src/generated/rest/nft.schema.ts +++ b/packages/data-apis/src/generated/rest/nft.schema.ts @@ -10,11 +10,7 @@ import type { operations } from "./nft.types.js"; export type GetNftsForOwnerResponse = operations["getNFTsForOwner-v3"]["responses"]["200"]["content"]["application/json"]; -/** - * Query params for getNFTsForOwner-v3. Sent via the URL at runtime; - * RestRequestSchema has no query channel, so this is exposed as a - * standalone type for the SDK's params layer. - */ +/** Query params for getNFTsForOwner-v3. */ export type GetNftsForOwnerQuery = NonNullable< operations["getNFTsForOwner-v3"]["parameters"]["query"] >; @@ -26,6 +22,7 @@ export type NftRestSchema = readonly [ Route: "getNFTsForOwner"; Method: "GET"; Body?: undefined; + Query: GetNftsForOwnerQuery; Response: GetNftsForOwnerResponse; }, ]; diff --git a/packages/data-apis/src/generated/rest/portfolio.schema.ts b/packages/data-apis/src/generated/rest/portfolio.schema.ts index 9a41ff79c4..a2860547d4 100644 --- a/packages/data-apis/src/generated/rest/portfolio.schema.ts +++ b/packages/data-apis/src/generated/rest/portfolio.schema.ts @@ -22,6 +22,7 @@ export type PortfolioRestSchema = readonly [ Route: "assets/tokens/by-address"; Method: "POST"; Body: GetTokensByAddressBody; + Query?: undefined; Response: GetTokensByAddressResponse; }, ]; diff --git a/packages/data-apis/src/generated/rest/prices.schema.ts b/packages/data-apis/src/generated/rest/prices.schema.ts index 556f6cca20..4b5b0df657 100644 --- a/packages/data-apis/src/generated/rest/prices.schema.ts +++ b/packages/data-apis/src/generated/rest/prices.schema.ts @@ -10,11 +10,7 @@ import type { operations } from "./prices.types.js"; export type GetTokenPricesBySymbolResponse = operations["get-token-prices-by-symbol"]["responses"]["200"]["content"]["application/json"]; -/** - * Query params for get-token-prices-by-symbol. Sent via the URL at runtime; - * RestRequestSchema has no query channel, so this is exposed as a - * standalone type for the SDK's params layer. - */ +/** Query params for get-token-prices-by-symbol. */ export type GetTokenPricesBySymbolQuery = NonNullable< operations["get-token-prices-by-symbol"]["parameters"]["query"] >; @@ -44,6 +40,7 @@ export type PricesRestSchema = readonly [ Route: "tokens/by-symbol"; Method: "GET"; Body?: undefined; + Query: GetTokenPricesBySymbolQuery; Response: GetTokenPricesBySymbolResponse; }, { @@ -51,6 +48,7 @@ export type PricesRestSchema = readonly [ Route: "tokens/by-address"; Method: "POST"; Body: GetTokenPricesByAddressBody; + Query?: undefined; Response: GetTokenPricesByAddressResponse; }, { @@ -58,6 +56,7 @@ export type PricesRestSchema = readonly [ Route: "tokens/historical"; Method: "POST"; Body: GetHistoricalTokenPricesBody; + Query?: undefined; Response: GetHistoricalTokenPricesResponse; }, ]; diff --git a/packages/data-apis/src/internal/clientHelpers.ts b/packages/data-apis/src/internal/clientHelpers.ts index 8f5fa05ec2..7702afbc55 100644 --- a/packages/data-apis/src/internal/clientHelpers.ts +++ b/packages/data-apis/src/internal/clientHelpers.ts @@ -13,6 +13,12 @@ import type { Chain, Client } from "viem"; /** The minimal client shape data actions operate on. */ export type DataClient = Client; +/** Per-request options accepted by data actions. */ +export type RequestOptions = { + /** Aborts the request (and any pending retries). */ + signal?: AbortSignal; +}; + /** * Reads the AlchemyTransportConfig back off an instantiated client transport. * The transport attaches its creation config to the transport value precisely From bdc4064d9c7bd958b81bd2d6bb3779cea8cf6e70 Mon Sep 17 00:00:00 2001 From: blake duncan Date: Wed, 10 Jun 2026 10:58:56 -0400 Subject: [PATCH 4/8] feat(data-apis): full v1 method surface (31 methods across 5 namespaces) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - portfolio: + getTokenBalancesByAddress, getNftsByAddress, getNftContractsByAddress (global Data API, multi-network bodies; per-entry fields like address-level filters preserved, network-slug enum deliberately widened for the escape hatch) - prices: getTokenPricesBySymbol (chain-agnostic GET), getTokenPricesByAddress (per-entry network resolution), getHistoricalTokenPrices (symbol or network+address forms) - nft: full v3 read surface — 21 actions (ownership/contract/collection listings, metadata + batch, owners, sales, floor price, search, spam/ airdrop/rarity checks). Mutations and deprecated/v2 ops excluded per scope plan. Bracketed wire keys (contractAddresses[], *Filters[]) exposed unbracketed in params and restored by the actions. - token: getTokenBalances (positional optionals trimmed), getTokenMetadata, getTokenAllowance over a shared getRpcRequest helper (also adopted by transfers.getAssetTransfers) - DataRpcSchema now aggregates transfers + token entries; REST actions all accept an options arg with an abort signal - 29 new wire-level tests (URL/method/body/query assertions per namespace) Co-Authored-By: Claude Fable 5 --- packages/data-apis/codegen.manifest.ts | 155 +++++++- .../src/actions/nft/computeRarity.ts | 35 ++ .../src/actions/nft/getCollectionMetadata.ts | 38 ++ .../src/actions/nft/getCollectionsForOwner.ts | 44 +++ .../src/actions/nft/getContractMetadata.ts | 38 ++ .../actions/nft/getContractMetadataBatch.ts | 39 ++ .../src/actions/nft/getContractsForOwner.ts | 44 +++ .../src/actions/nft/getFloorPrice.ts | 35 ++ .../src/actions/nft/getNftMetadata.ts | 38 ++ .../src/actions/nft/getNftMetadataBatch.ts | 39 ++ .../data-apis/src/actions/nft/getNftSales.ts | 35 ++ .../src/actions/nft/getNftsForCollection.ts | 38 ++ .../src/actions/nft/getNftsForContract.ts | 38 ++ .../src/actions/nft/getNftsForOwner.ts | 10 +- .../src/actions/nft/getOwnersForContract.ts | 38 ++ .../src/actions/nft/getOwnersForNft.ts | 38 ++ .../src/actions/nft/getSpamContracts.ts | 37 ++ .../data-apis/src/actions/nft/isAirdropNft.ts | 35 ++ .../src/actions/nft/isHolderOfContract.ts | 38 ++ .../src/actions/nft/isSpamContract.ts | 38 ++ .../data-apis/src/actions/nft/nft.test.ts | 175 +++++++++ .../src/actions/nft/searchContractMetadata.ts | 38 ++ .../src/actions/nft/summarizeNftAttributes.ts | 38 ++ .../portfolio/getNftContractsByAddress.ts | 47 +++ .../src/actions/portfolio/getNftsByAddress.ts | 47 +++ .../portfolio/getTokenBalancesByAddress.ts | 47 +++ .../actions/portfolio/getTokensByAddress.ts | 8 +- .../src/actions/portfolio/portfolio.test.ts | 63 ++++ .../prices/getHistoricalTokenPrices.ts | 44 +++ .../actions/prices/getTokenPricesByAddress.ts | 41 +++ .../actions/prices/getTokenPricesBySymbol.ts | 35 ++ .../src/actions/prices/prices.test.ts | 84 +++++ .../src/actions/token/getTokenAllowance.ts | 30 ++ .../src/actions/token/getTokenBalances.ts | 42 +++ .../src/actions/token/getTokenMetadata.ts | 30 ++ .../data-apis/src/actions/token/token.test.ts | 76 ++++ .../actions/transfers/getAssetTransfers.ts | 21 +- packages/data-apis/src/decorator.ts | 232 ++++++++++-- .../src/generated/rest/nft.schema.ts | 335 ++++++++++++++++++ .../src/generated/rest/portfolio.schema.ts | 51 +++ packages/data-apis/src/index.ts | 38 +- .../data-apis/src/internal/clientHelpers.ts | 30 +- packages/data-apis/src/internal/endpoints.ts | 3 + packages/data-apis/src/internal/query.ts | 19 + packages/data-apis/src/schema/rest.ts | 1 + packages/data-apis/src/schema/rpc.ts | 16 +- packages/data-apis/src/types.ts | 253 ++++++++++++- 47 files changed, 2618 insertions(+), 76 deletions(-) create mode 100644 packages/data-apis/src/actions/nft/computeRarity.ts create mode 100644 packages/data-apis/src/actions/nft/getCollectionMetadata.ts create mode 100644 packages/data-apis/src/actions/nft/getCollectionsForOwner.ts create mode 100644 packages/data-apis/src/actions/nft/getContractMetadata.ts create mode 100644 packages/data-apis/src/actions/nft/getContractMetadataBatch.ts create mode 100644 packages/data-apis/src/actions/nft/getContractsForOwner.ts create mode 100644 packages/data-apis/src/actions/nft/getFloorPrice.ts create mode 100644 packages/data-apis/src/actions/nft/getNftMetadata.ts create mode 100644 packages/data-apis/src/actions/nft/getNftMetadataBatch.ts create mode 100644 packages/data-apis/src/actions/nft/getNftSales.ts create mode 100644 packages/data-apis/src/actions/nft/getNftsForCollection.ts create mode 100644 packages/data-apis/src/actions/nft/getNftsForContract.ts create mode 100644 packages/data-apis/src/actions/nft/getOwnersForContract.ts create mode 100644 packages/data-apis/src/actions/nft/getOwnersForNft.ts create mode 100644 packages/data-apis/src/actions/nft/getSpamContracts.ts create mode 100644 packages/data-apis/src/actions/nft/isAirdropNft.ts create mode 100644 packages/data-apis/src/actions/nft/isHolderOfContract.ts create mode 100644 packages/data-apis/src/actions/nft/isSpamContract.ts create mode 100644 packages/data-apis/src/actions/nft/nft.test.ts create mode 100644 packages/data-apis/src/actions/nft/searchContractMetadata.ts create mode 100644 packages/data-apis/src/actions/nft/summarizeNftAttributes.ts create mode 100644 packages/data-apis/src/actions/portfolio/getNftContractsByAddress.ts create mode 100644 packages/data-apis/src/actions/portfolio/getNftsByAddress.ts create mode 100644 packages/data-apis/src/actions/portfolio/getTokenBalancesByAddress.ts create mode 100644 packages/data-apis/src/actions/portfolio/portfolio.test.ts create mode 100644 packages/data-apis/src/actions/prices/getHistoricalTokenPrices.ts create mode 100644 packages/data-apis/src/actions/prices/getTokenPricesByAddress.ts create mode 100644 packages/data-apis/src/actions/prices/getTokenPricesBySymbol.ts create mode 100644 packages/data-apis/src/actions/prices/prices.test.ts create mode 100644 packages/data-apis/src/actions/token/getTokenAllowance.ts create mode 100644 packages/data-apis/src/actions/token/getTokenBalances.ts create mode 100644 packages/data-apis/src/actions/token/getTokenMetadata.ts create mode 100644 packages/data-apis/src/actions/token/token.test.ts create mode 100644 packages/data-apis/src/internal/query.ts diff --git a/packages/data-apis/codegen.manifest.ts b/packages/data-apis/codegen.manifest.ts index a2b33f5d12..c138187edb 100644 --- a/packages/data-apis/codegen.manifest.ts +++ b/packages/data-apis/codegen.manifest.ts @@ -2,35 +2,61 @@ import type { CodegenManifest } from "@alchemy/api-codegen"; // The hand-maintained overlay mapping spec operations to this package's // generated internals (src/generated/). Validated against the committed spec -// snapshots on every `pnpm generate` — referencing a renamed/removed spec -// operation is a hard error. Public naming and pagination semantics stay -// human decisions; everything type-shaped is generated. +// snapshots on every `pnpm generate` — referencing a renamed/removed/ +// deprecated spec operation is a hard error, and pagination metadata is +// checked against request/response schemas. Public naming and pagination +// semantics stay human decisions; everything type-shaped is generated. +// +// Deliberately excluded: NFT v2 legacy duplicates, and the v3 mutation +// operations (invalidateContract-v3, reportSpam-v3, refreshNftMetadata-v3) +// per the data SDK scope plan. export default { rest: [ { spec: "portfolio", schemaTypeName: "PortfolioRestSchema", - // Spec path: POST /{apiKey}/assets/tokens/by-address. Runtime auth is - // header-based against https://api.g.alchemy.com/data/v1. + // Spec paths: POST /{apiKey}/assets/... Runtime auth is header-based + // against https://api.g.alchemy.com/data/v1. pathRules: { stripApiKeySegment: true }, operations: [ { operationId: "get-tokens-by-address", exportBaseName: "GetTokensByAddress", }, + { + operationId: "get-token-balances-by-address", + exportBaseName: "GetTokenBalancesByAddress", + }, + { + operationId: "get-nfts-by-address", + exportBaseName: "GetNftsByAddress", + pagination: { + pageParam: "pageKey", + responseCursorField: "data.pageKey", + itemsField: "data.ownedNfts", + }, + }, + { + operationId: "get-nft-contracts-by-address", + exportBaseName: "GetNftContractsByAddress", + pagination: { + pageParam: "pageKey", + responseCursorField: "data.pageKey", + itemsField: "data.contracts", + }, + }, ], }, { spec: "prices", schemaTypeName: "PricesRestSchema", - // Spec paths: /{apiKey}/tokens/by-symbol etc. Runtime auth is - // header-based against https://api.g.alchemy.com/prices/v1. + // Spec paths: /{apiKey}/tokens/... Runtime auth is header-based + // against https://api.g.alchemy.com/prices/v1. pathRules: { stripApiKeySegment: true }, operations: [ { operationId: "get-token-prices-by-symbol", exportBaseName: "GetTokenPricesBySymbol", - emitQueryType: true, }, { operationId: "get-token-prices-by-address", @@ -45,7 +71,7 @@ export default { { spec: "nft", schemaTypeName: "NftRestSchema", - // Spec path: GET /v3/{apiKey}/getNFTsForOwner. Runtime base URL is + // Spec paths: /v3/{apiKey}/. Runtime base URL is // https://{network}.g.alchemy.com/nft/v3, so /v3 is stripped too. pathRules: { stripApiKeySegment: true, stripPrefix: "/v3" }, operations: [ @@ -58,6 +84,113 @@ export default { itemsField: "ownedNfts", }, }, + { + operationId: "getNFTsForContract-v3", + exportBaseName: "GetNftsForContract", + pagination: { + pageParam: "startToken", + responseCursorField: "pageKey", + itemsField: "nfts", + }, + }, + { + operationId: "getNFTsForCollection-v3", + exportBaseName: "GetNftsForCollection", + pagination: { + pageParam: "startToken", + responseCursorField: "nextToken", + itemsField: "nfts", + }, + }, + { + operationId: "getNFTMetadata-v3", + exportBaseName: "GetNftMetadata", + }, + { + operationId: "getNFTMetadataBatch-v3", + exportBaseName: "GetNftMetadataBatch", + }, + { + operationId: "getContractMetadata-v3", + exportBaseName: "GetContractMetadata", + }, + { + operationId: "getContractMetadataBatch-v3", + exportBaseName: "GetContractMetadataBatch", + }, + { + operationId: "getCollectionMetadata-v3", + exportBaseName: "GetCollectionMetadata", + }, + { + operationId: "getContractsForOwner-v3", + exportBaseName: "GetContractsForOwner", + pagination: { + pageParam: "pageKey", + responseCursorField: "pageKey", + itemsField: "contracts", + }, + }, + { + operationId: "getCollectionsForOwner-v3", + exportBaseName: "GetCollectionsForOwner", + pagination: { + pageParam: "pageKey", + responseCursorField: "pageKey", + itemsField: "collections", + }, + }, + { + operationId: "getOwnersForNFT-v3", + exportBaseName: "GetOwnersForNft", + }, + { + // Note: request takes pageKey but the response declares no cursor + // field, so no pagination metadata (and no Pages companion). + operationId: "getOwnersForContract-v3", + exportBaseName: "GetOwnersForContract", + }, + { + operationId: "getNFTSales-v3", + exportBaseName: "GetNftSales", + pagination: { + pageParam: "pageKey", + responseCursorField: "pageKey", + itemsField: "nftSales", + }, + }, + { + operationId: "getFloorPrice-v3", + exportBaseName: "GetFloorPrice", + }, + { + operationId: "searchContractMetadata-v3", + exportBaseName: "SearchContractMetadata", + }, + { + operationId: "getSpamContracts-v3", + exportBaseName: "GetSpamContracts", + }, + { + operationId: "isSpamContract-v3", + exportBaseName: "IsSpamContract", + }, + { + operationId: "isAirdropNFT-v3", + exportBaseName: "IsAirdropNft", + }, + { + operationId: "isHolderOfContract-v3", + exportBaseName: "IsHolderOfContract", + }, + { + operationId: "computeRarity-v3", + exportBaseName: "ComputeRarity", + }, + { + operationId: "summarizeNFTAttributes-v3", + exportBaseName: "SummarizeNftAttributes", + }, ], }, ], @@ -82,6 +215,10 @@ export default { schemaTypeName: "TokenRpcSchema", methods: [ { + // No pagination metadata: the docs spec omits pageKey from the + // result schema even though the live API returns one when + // paginating — a spec gap to raise with the docs team. Callers can + // still page manually via options.pageKey. method: "alchemy_getTokenBalances", exportBaseName: "AlchemyGetTokenBalances", }, diff --git a/packages/data-apis/src/actions/nft/computeRarity.ts b/packages/data-apis/src/actions/nft/computeRarity.ts new file mode 100644 index 0000000000..b9f09f0a73 --- /dev/null +++ b/packages/data-apis/src/actions/nft/computeRarity.ts @@ -0,0 +1,35 @@ +import { getNftApiUrl } from "../../internal/endpoints.js"; +import { + getRestClient, + resolveRequestNetwork, + type DataClient, + type RequestOptions, +} from "../../internal/clientHelpers.js"; +import type { NftRestSchema } from "../../schema/rest.js"; +import type { ComputeRarityParams, ComputeRarityResult } from "../../types.js"; + +/** + * Computes attribute rarity for a specific NFT. The network is resolved per + * request: an explicit `network` param wins, otherwise the client's + * configured network/chain applies. + * + * @param {DataClient} client A client configured with an Alchemy transport + * @param {ComputeRarityParams} params Contract address, token id, and optional network override + * @param {RequestOptions} [options] Per-request options (abort signal) + * @returns {Promise} Rarity scores per attribute + */ +export async function computeRarity( + client: DataClient, + params: ComputeRarityParams, + options?: RequestOptions, +): Promise { + const { network, ...query } = params; + const { slug } = resolveRequestNetwork(client, network); + const restClient = getRestClient(client, getNftApiUrl(slug)); + return restClient.request({ + route: "computeRarity", + method: "GET", + query, + signal: options?.signal, + }); +} diff --git a/packages/data-apis/src/actions/nft/getCollectionMetadata.ts b/packages/data-apis/src/actions/nft/getCollectionMetadata.ts new file mode 100644 index 0000000000..49b2af2af9 --- /dev/null +++ b/packages/data-apis/src/actions/nft/getCollectionMetadata.ts @@ -0,0 +1,38 @@ +import { getNftApiUrl } from "../../internal/endpoints.js"; +import { + getRestClient, + resolveRequestNetwork, + type DataClient, + type RequestOptions, +} from "../../internal/clientHelpers.js"; +import type { NftRestSchema } from "../../schema/rest.js"; +import type { + GetCollectionMetadataParams, + GetCollectionMetadataResult, +} from "../../types.js"; + +/** + * Fetches metadata for an NFT collection by slug. The network is resolved per + * request: an explicit `network` param wins, otherwise the client's + * configured network/chain applies. + * + * @param {DataClient} client A client configured with an Alchemy transport + * @param {GetCollectionMetadataParams} params Collection slug and optional network override + * @param {RequestOptions} [options] Per-request options (abort signal) + * @returns {Promise} The collection's metadata + */ +export async function getCollectionMetadata( + client: DataClient, + params: GetCollectionMetadataParams, + options?: RequestOptions, +): Promise { + const { network, ...query } = params; + const { slug } = resolveRequestNetwork(client, network); + const restClient = getRestClient(client, getNftApiUrl(slug)); + return restClient.request({ + route: "getCollectionMetadata", + method: "GET", + query, + signal: options?.signal, + }); +} diff --git a/packages/data-apis/src/actions/nft/getCollectionsForOwner.ts b/packages/data-apis/src/actions/nft/getCollectionsForOwner.ts new file mode 100644 index 0000000000..16f9350573 --- /dev/null +++ b/packages/data-apis/src/actions/nft/getCollectionsForOwner.ts @@ -0,0 +1,44 @@ +import { getNftApiUrl } from "../../internal/endpoints.js"; +import { + getRestClient, + resolveRequestNetwork, + type DataClient, + type RequestOptions, +} from "../../internal/clientHelpers.js"; +import { bracketArrayKeys } from "../../internal/query.js"; +import type { GetCollectionsForOwnerQuery } from "../../generated/rest/nft.schema.js"; +import type { NftRestSchema } from "../../schema/rest.js"; +import type { + GetCollectionsForOwnerParams, + GetCollectionsForOwnerResult, +} from "../../types.js"; + +/** + * Fetches all NFT collections an address holds tokens from. The network is + * resolved per request: an explicit `network` param wins, otherwise the + * client's configured network/chain applies. + * + * @param {DataClient} client A client configured with an Alchemy transport + * @param {GetCollectionsForOwnerParams} params Owner address, optional network override, and filters + * @param {RequestOptions} [options] Per-request options (abort signal) + * @returns {Promise} The owned collections and pagination cursor + */ +export async function getCollectionsForOwner( + client: DataClient, + params: GetCollectionsForOwnerParams, + options?: RequestOptions, +): Promise { + const { network, ...rest } = params; + const { slug } = resolveRequestNetwork(client, network); + + const restClient = getRestClient(client, getNftApiUrl(slug)); + return restClient.request({ + route: "getCollectionsForOwner", + method: "GET", + query: bracketArrayKeys(rest, [ + "excludeFilters", + "includeFilters", + ]) as GetCollectionsForOwnerQuery, + signal: options?.signal, + }); +} diff --git a/packages/data-apis/src/actions/nft/getContractMetadata.ts b/packages/data-apis/src/actions/nft/getContractMetadata.ts new file mode 100644 index 0000000000..ed82ccc272 --- /dev/null +++ b/packages/data-apis/src/actions/nft/getContractMetadata.ts @@ -0,0 +1,38 @@ +import { getNftApiUrl } from "../../internal/endpoints.js"; +import { + getRestClient, + resolveRequestNetwork, + type DataClient, + type RequestOptions, +} from "../../internal/clientHelpers.js"; +import type { NftRestSchema } from "../../schema/rest.js"; +import type { + GetContractMetadataParams, + GetContractMetadataResult, +} from "../../types.js"; + +/** + * Fetches metadata for an NFT contract. The network is resolved per + * request: an explicit `network` param wins, otherwise the client's + * configured network/chain applies. + * + * @param {DataClient} client A client configured with an Alchemy transport + * @param {GetContractMetadataParams} params Contract address and optional network override + * @param {RequestOptions} [options] Per-request options (abort signal) + * @returns {Promise} The contract's metadata + */ +export async function getContractMetadata( + client: DataClient, + params: GetContractMetadataParams, + options?: RequestOptions, +): Promise { + const { network, ...query } = params; + const { slug } = resolveRequestNetwork(client, network); + const restClient = getRestClient(client, getNftApiUrl(slug)); + return restClient.request({ + route: "getContractMetadata", + method: "GET", + query, + signal: options?.signal, + }); +} diff --git a/packages/data-apis/src/actions/nft/getContractMetadataBatch.ts b/packages/data-apis/src/actions/nft/getContractMetadataBatch.ts new file mode 100644 index 0000000000..bc04a522ef --- /dev/null +++ b/packages/data-apis/src/actions/nft/getContractMetadataBatch.ts @@ -0,0 +1,39 @@ +import { getNftApiUrl } from "../../internal/endpoints.js"; +import { + getRestClient, + resolveRequestNetwork, + type DataClient, + type RequestOptions, +} from "../../internal/clientHelpers.js"; +import type { NftRestSchema } from "../../schema/rest.js"; +import type { + GetContractMetadataBatchParams, + GetContractMetadataBatchResult, +} from "../../types.js"; + +/** + * Fetches metadata for multiple NFT contracts in one call. The network is + * resolved per request: an explicit `network` param wins, otherwise the + * client's configured network/chain applies. + * + * @param {DataClient} client A client configured with an Alchemy transport + * @param {GetContractMetadataBatchParams} params The contract addresses and optional network override + * @param {RequestOptions} [options] Per-request options (abort signal) + * @returns {Promise} Metadata for each requested contract + */ +export async function getContractMetadataBatch( + client: DataClient, + params: GetContractMetadataBatchParams, + options?: RequestOptions, +): Promise { + const { network, ...body } = params; + const { slug } = resolveRequestNetwork(client, network); + + const restClient = getRestClient(client, getNftApiUrl(slug)); + return restClient.request({ + route: "getContractMetadataBatch", + method: "POST", + body, + signal: options?.signal, + }); +} diff --git a/packages/data-apis/src/actions/nft/getContractsForOwner.ts b/packages/data-apis/src/actions/nft/getContractsForOwner.ts new file mode 100644 index 0000000000..67c38fe9c6 --- /dev/null +++ b/packages/data-apis/src/actions/nft/getContractsForOwner.ts @@ -0,0 +1,44 @@ +import { getNftApiUrl } from "../../internal/endpoints.js"; +import { + getRestClient, + resolveRequestNetwork, + type DataClient, + type RequestOptions, +} from "../../internal/clientHelpers.js"; +import { bracketArrayKeys } from "../../internal/query.js"; +import type { GetContractsForOwnerQuery } from "../../generated/rest/nft.schema.js"; +import type { NftRestSchema } from "../../schema/rest.js"; +import type { + GetContractsForOwnerParams, + GetContractsForOwnerResult, +} from "../../types.js"; + +/** + * Fetches all NFT contracts an address holds tokens from. The network is + * resolved per request: an explicit `network` param wins, otherwise the + * client's configured network/chain applies. + * + * @param {DataClient} client A client configured with an Alchemy transport + * @param {GetContractsForOwnerParams} params Owner address, optional network override, and filters + * @param {RequestOptions} [options] Per-request options (abort signal) + * @returns {Promise} The owned contracts and pagination cursor + */ +export async function getContractsForOwner( + client: DataClient, + params: GetContractsForOwnerParams, + options?: RequestOptions, +): Promise { + const { network, ...rest } = params; + const { slug } = resolveRequestNetwork(client, network); + + const restClient = getRestClient(client, getNftApiUrl(slug)); + return restClient.request({ + route: "getContractsForOwner", + method: "GET", + query: bracketArrayKeys(rest, [ + "excludeFilters", + "includeFilters", + ]) as GetContractsForOwnerQuery, + signal: options?.signal, + }); +} diff --git a/packages/data-apis/src/actions/nft/getFloorPrice.ts b/packages/data-apis/src/actions/nft/getFloorPrice.ts new file mode 100644 index 0000000000..0520bb938a --- /dev/null +++ b/packages/data-apis/src/actions/nft/getFloorPrice.ts @@ -0,0 +1,35 @@ +import { getNftApiUrl } from "../../internal/endpoints.js"; +import { + getRestClient, + resolveRequestNetwork, + type DataClient, + type RequestOptions, +} from "../../internal/clientHelpers.js"; +import type { NftRestSchema } from "../../schema/rest.js"; +import type { GetFloorPriceParams, GetFloorPriceResult } from "../../types.js"; + +/** + * Fetches marketplace floor prices for an NFT contract or collection. The network is resolved per + * request: an explicit `network` param wins, otherwise the client's + * configured network/chain applies. + * + * @param {DataClient} client A client configured with an Alchemy transport + * @param {GetFloorPriceParams} params Contract address or collection slug, and optional network override + * @param {RequestOptions} [options] Per-request options (abort signal) + * @returns {Promise} Floor prices per marketplace + */ +export async function getFloorPrice( + client: DataClient, + params: GetFloorPriceParams, + options?: RequestOptions, +): Promise { + const { network, ...query } = params; + const { slug } = resolveRequestNetwork(client, network); + const restClient = getRestClient(client, getNftApiUrl(slug)); + return restClient.request({ + route: "getFloorPrice", + method: "GET", + query, + signal: options?.signal, + }); +} diff --git a/packages/data-apis/src/actions/nft/getNftMetadata.ts b/packages/data-apis/src/actions/nft/getNftMetadata.ts new file mode 100644 index 0000000000..21f52fa43a --- /dev/null +++ b/packages/data-apis/src/actions/nft/getNftMetadata.ts @@ -0,0 +1,38 @@ +import { getNftApiUrl } from "../../internal/endpoints.js"; +import { + getRestClient, + resolveRequestNetwork, + type DataClient, + type RequestOptions, +} from "../../internal/clientHelpers.js"; +import type { NftRestSchema } from "../../schema/rest.js"; +import type { + GetNftMetadataParams, + GetNftMetadataResult, +} from "../../types.js"; + +/** + * Fetches metadata for a single NFT. The network is resolved per + * request: an explicit `network` param wins, otherwise the client's + * configured network/chain applies. + * + * @param {DataClient} client A client configured with an Alchemy transport + * @param {GetNftMetadataParams} params Contract address, token id, optional network override, and cache options + * @param {RequestOptions} [options] Per-request options (abort signal) + * @returns {Promise} The NFT's metadata + */ +export async function getNftMetadata( + client: DataClient, + params: GetNftMetadataParams, + options?: RequestOptions, +): Promise { + const { network, ...query } = params; + const { slug } = resolveRequestNetwork(client, network); + const restClient = getRestClient(client, getNftApiUrl(slug)); + return restClient.request({ + route: "getNFTMetadata", + method: "GET", + query, + signal: options?.signal, + }); +} diff --git a/packages/data-apis/src/actions/nft/getNftMetadataBatch.ts b/packages/data-apis/src/actions/nft/getNftMetadataBatch.ts new file mode 100644 index 0000000000..344ad6fe1a --- /dev/null +++ b/packages/data-apis/src/actions/nft/getNftMetadataBatch.ts @@ -0,0 +1,39 @@ +import { getNftApiUrl } from "../../internal/endpoints.js"; +import { + getRestClient, + resolveRequestNetwork, + type DataClient, + type RequestOptions, +} from "../../internal/clientHelpers.js"; +import type { NftRestSchema } from "../../schema/rest.js"; +import type { + GetNftMetadataBatchParams, + GetNftMetadataBatchResult, +} from "../../types.js"; + +/** + * Fetches metadata for up to 100 NFTs in one call. The network is resolved + * per request: an explicit `network` param wins, otherwise the client's + * configured network/chain applies. + * + * @param {DataClient} client A client configured with an Alchemy transport + * @param {GetNftMetadataBatchParams} params The tokens to look up, cache options, and optional network override + * @param {RequestOptions} [options] Per-request options (abort signal) + * @returns {Promise} Metadata for each requested NFT + */ +export async function getNftMetadataBatch( + client: DataClient, + params: GetNftMetadataBatchParams, + options?: RequestOptions, +): Promise { + const { network, ...body } = params; + const { slug } = resolveRequestNetwork(client, network); + + const restClient = getRestClient(client, getNftApiUrl(slug)); + return restClient.request({ + route: "getNFTMetadataBatch", + method: "POST", + body, + signal: options?.signal, + }); +} diff --git a/packages/data-apis/src/actions/nft/getNftSales.ts b/packages/data-apis/src/actions/nft/getNftSales.ts new file mode 100644 index 0000000000..b7e43d680c --- /dev/null +++ b/packages/data-apis/src/actions/nft/getNftSales.ts @@ -0,0 +1,35 @@ +import { getNftApiUrl } from "../../internal/endpoints.js"; +import { + getRestClient, + resolveRequestNetwork, + type DataClient, + type RequestOptions, +} from "../../internal/clientHelpers.js"; +import type { NftRestSchema } from "../../schema/rest.js"; +import type { GetNftSalesParams, GetNftSalesResult } from "../../types.js"; + +/** + * Fetches NFT sales matching the given filters. The network is resolved per + * request: an explicit `network` param wins, otherwise the client's + * configured network/chain applies. + * + * @param {DataClient} client A client configured with an Alchemy transport + * @param {GetNftSalesParams} params Sale filters, optional network override, and paging options + * @param {RequestOptions} [options] Per-request options (abort signal) + * @returns {Promise} The matching sales and pagination cursor + */ +export async function getNftSales( + client: DataClient, + params: GetNftSalesParams, + options?: RequestOptions, +): Promise { + const { network, ...query } = params; + const { slug } = resolveRequestNetwork(client, network); + const restClient = getRestClient(client, getNftApiUrl(slug)); + return restClient.request({ + route: "getNFTSales", + method: "GET", + query, + signal: options?.signal, + }); +} diff --git a/packages/data-apis/src/actions/nft/getNftsForCollection.ts b/packages/data-apis/src/actions/nft/getNftsForCollection.ts new file mode 100644 index 0000000000..f2bcdaffe8 --- /dev/null +++ b/packages/data-apis/src/actions/nft/getNftsForCollection.ts @@ -0,0 +1,38 @@ +import { getNftApiUrl } from "../../internal/endpoints.js"; +import { + getRestClient, + resolveRequestNetwork, + type DataClient, + type RequestOptions, +} from "../../internal/clientHelpers.js"; +import type { NftRestSchema } from "../../schema/rest.js"; +import type { + GetNftsForCollectionParams, + GetNftsForCollectionResult, +} from "../../types.js"; + +/** + * Fetches all NFTs for a given collection (by contract address or collection slug). The network is resolved per + * request: an explicit `network` param wins, otherwise the client's + * configured network/chain applies. + * + * @param {DataClient} client A client configured with an Alchemy transport + * @param {GetNftsForCollectionParams} params Collection identifier, optional network override, and paging filters + * @param {RequestOptions} [options] Per-request options (abort signal) + * @returns {Promise} The collection's NFTs and next-page token + */ +export async function getNftsForCollection( + client: DataClient, + params: GetNftsForCollectionParams, + options?: RequestOptions, +): Promise { + const { network, ...query } = params; + const { slug } = resolveRequestNetwork(client, network); + const restClient = getRestClient(client, getNftApiUrl(slug)); + return restClient.request({ + route: "getNFTsForCollection", + method: "GET", + query, + signal: options?.signal, + }); +} diff --git a/packages/data-apis/src/actions/nft/getNftsForContract.ts b/packages/data-apis/src/actions/nft/getNftsForContract.ts new file mode 100644 index 0000000000..9ac9047379 --- /dev/null +++ b/packages/data-apis/src/actions/nft/getNftsForContract.ts @@ -0,0 +1,38 @@ +import { getNftApiUrl } from "../../internal/endpoints.js"; +import { + getRestClient, + resolveRequestNetwork, + type DataClient, + type RequestOptions, +} from "../../internal/clientHelpers.js"; +import type { NftRestSchema } from "../../schema/rest.js"; +import type { + GetNftsForContractParams, + GetNftsForContractResult, +} from "../../types.js"; + +/** + * Fetches all NFTs for a given contract. The network is resolved per + * request: an explicit `network` param wins, otherwise the client's + * configured network/chain applies. + * + * @param {DataClient} client A client configured with an Alchemy transport + * @param {GetNftsForContractParams} params Contract address, optional network override, and paging filters + * @param {RequestOptions} [options] Per-request options (abort signal) + * @returns {Promise} The contract's NFTs and pagination cursor + */ +export async function getNftsForContract( + client: DataClient, + params: GetNftsForContractParams, + options?: RequestOptions, +): Promise { + const { network, ...query } = params; + const { slug } = resolveRequestNetwork(client, network); + const restClient = getRestClient(client, getNftApiUrl(slug)); + return restClient.request({ + route: "getNFTsForContract", + method: "GET", + query, + signal: options?.signal, + }); +} diff --git a/packages/data-apis/src/actions/nft/getNftsForOwner.ts b/packages/data-apis/src/actions/nft/getNftsForOwner.ts index b8a9736f92..8eda9d1c0a 100644 --- a/packages/data-apis/src/actions/nft/getNftsForOwner.ts +++ b/packages/data-apis/src/actions/nft/getNftsForOwner.ts @@ -5,6 +5,8 @@ import { type DataClient, type RequestOptions, } from "../../internal/clientHelpers.js"; +import { bracketArrayKeys } from "../../internal/query.js"; +import type { GetNftsForOwnerQuery } from "../../generated/rest/nft.schema.js"; import type { NftRestSchema } from "../../schema/rest.js"; import type { GetNftsForOwnerParams, @@ -26,14 +28,18 @@ export async function getNftsForOwner( params: GetNftsForOwnerParams, options?: RequestOptions, ): Promise { - const { network, contractAddresses, ...query } = params; + const { network, ...rest } = params; const { slug } = resolveRequestNetwork(client, network); const restClient = getRestClient(client, getNftApiUrl(slug)); return restClient.request({ route: "getNFTsForOwner", method: "GET", - query: { ...query, "contractAddresses[]": contractAddresses }, + query: bracketArrayKeys(rest, [ + "contractAddresses", + "excludeFilters", + "includeFilters", + ]) as GetNftsForOwnerQuery, signal: options?.signal, }); } diff --git a/packages/data-apis/src/actions/nft/getOwnersForContract.ts b/packages/data-apis/src/actions/nft/getOwnersForContract.ts new file mode 100644 index 0000000000..74550d8f72 --- /dev/null +++ b/packages/data-apis/src/actions/nft/getOwnersForContract.ts @@ -0,0 +1,38 @@ +import { getNftApiUrl } from "../../internal/endpoints.js"; +import { + getRestClient, + resolveRequestNetwork, + type DataClient, + type RequestOptions, +} from "../../internal/clientHelpers.js"; +import type { NftRestSchema } from "../../schema/rest.js"; +import type { + GetOwnersForContractParams, + GetOwnersForContractResult, +} from "../../types.js"; + +/** + * Fetches all owners for an NFT contract. The network is resolved per + * request: an explicit `network` param wins, otherwise the client's + * configured network/chain applies. + * + * @param {DataClient} client A client configured with an Alchemy transport + * @param {GetOwnersForContractParams} params Contract address, optional network override, and balance options + * @param {RequestOptions} [options] Per-request options (abort signal) + * @returns {Promise} The contract's owners + */ +export async function getOwnersForContract( + client: DataClient, + params: GetOwnersForContractParams, + options?: RequestOptions, +): Promise { + const { network, ...query } = params; + const { slug } = resolveRequestNetwork(client, network); + const restClient = getRestClient(client, getNftApiUrl(slug)); + return restClient.request({ + route: "getOwnersForContract", + method: "GET", + query, + signal: options?.signal, + }); +} diff --git a/packages/data-apis/src/actions/nft/getOwnersForNft.ts b/packages/data-apis/src/actions/nft/getOwnersForNft.ts new file mode 100644 index 0000000000..715abd9e9e --- /dev/null +++ b/packages/data-apis/src/actions/nft/getOwnersForNft.ts @@ -0,0 +1,38 @@ +import { getNftApiUrl } from "../../internal/endpoints.js"; +import { + getRestClient, + resolveRequestNetwork, + type DataClient, + type RequestOptions, +} from "../../internal/clientHelpers.js"; +import type { NftRestSchema } from "../../schema/rest.js"; +import type { + GetOwnersForNftParams, + GetOwnersForNftResult, +} from "../../types.js"; + +/** + * Fetches the owners of a specific NFT. The network is resolved per + * request: an explicit `network` param wins, otherwise the client's + * configured network/chain applies. + * + * @param {DataClient} client A client configured with an Alchemy transport + * @param {GetOwnersForNftParams} params Contract address, token id, and optional network override + * @param {RequestOptions} [options] Per-request options (abort signal) + * @returns {Promise} The NFT's owners + */ +export async function getOwnersForNft( + client: DataClient, + params: GetOwnersForNftParams, + options?: RequestOptions, +): Promise { + const { network, ...query } = params; + const { slug } = resolveRequestNetwork(client, network); + const restClient = getRestClient(client, getNftApiUrl(slug)); + return restClient.request({ + route: "getOwnersForNFT", + method: "GET", + query, + signal: options?.signal, + }); +} diff --git a/packages/data-apis/src/actions/nft/getSpamContracts.ts b/packages/data-apis/src/actions/nft/getSpamContracts.ts new file mode 100644 index 0000000000..a750336758 --- /dev/null +++ b/packages/data-apis/src/actions/nft/getSpamContracts.ts @@ -0,0 +1,37 @@ +import { getNftApiUrl } from "../../internal/endpoints.js"; +import { + getRestClient, + resolveRequestNetwork, + type DataClient, + type RequestOptions, +} from "../../internal/clientHelpers.js"; +import type { NftRestSchema } from "../../schema/rest.js"; +import type { + GetSpamContractsParams, + GetSpamContractsResult, +} from "../../types.js"; + +/** + * Fetches the full list of contracts classified as spam on a network. The + * network is resolved per request: an explicit `network` param wins, + * otherwise the client's configured network/chain applies. + * + * @param {DataClient} client A client configured with an Alchemy transport + * @param {GetSpamContractsParams} [params] Optional network override + * @param {RequestOptions} [options] Per-request options (abort signal) + * @returns {Promise} The spam contract addresses + */ +export async function getSpamContracts( + client: DataClient, + params: GetSpamContractsParams = {}, + options?: RequestOptions, +): Promise { + const { slug } = resolveRequestNetwork(client, params.network); + + const restClient = getRestClient(client, getNftApiUrl(slug)); + return restClient.request({ + route: "getSpamContracts", + method: "GET", + signal: options?.signal, + }); +} diff --git a/packages/data-apis/src/actions/nft/isAirdropNft.ts b/packages/data-apis/src/actions/nft/isAirdropNft.ts new file mode 100644 index 0000000000..2f27da3b75 --- /dev/null +++ b/packages/data-apis/src/actions/nft/isAirdropNft.ts @@ -0,0 +1,35 @@ +import { getNftApiUrl } from "../../internal/endpoints.js"; +import { + getRestClient, + resolveRequestNetwork, + type DataClient, + type RequestOptions, +} from "../../internal/clientHelpers.js"; +import type { NftRestSchema } from "../../schema/rest.js"; +import type { IsAirdropNftParams, IsAirdropNftResult } from "../../types.js"; + +/** + * Checks whether an NFT was airdropped to its owner. The network is resolved per + * request: an explicit `network` param wins, otherwise the client's + * configured network/chain applies. + * + * @param {DataClient} client A client configured with an Alchemy transport + * @param {IsAirdropNftParams} params Contract address, token id, and optional network override + * @param {RequestOptions} [options] Per-request options (abort signal) + * @returns {Promise} The airdrop classification + */ +export async function isAirdropNft( + client: DataClient, + params: IsAirdropNftParams, + options?: RequestOptions, +): Promise { + const { network, ...query } = params; + const { slug } = resolveRequestNetwork(client, network); + const restClient = getRestClient(client, getNftApiUrl(slug)); + return restClient.request({ + route: "isAirdropNFT", + method: "GET", + query, + signal: options?.signal, + }); +} diff --git a/packages/data-apis/src/actions/nft/isHolderOfContract.ts b/packages/data-apis/src/actions/nft/isHolderOfContract.ts new file mode 100644 index 0000000000..1da25701e1 --- /dev/null +++ b/packages/data-apis/src/actions/nft/isHolderOfContract.ts @@ -0,0 +1,38 @@ +import { getNftApiUrl } from "../../internal/endpoints.js"; +import { + getRestClient, + resolveRequestNetwork, + type DataClient, + type RequestOptions, +} from "../../internal/clientHelpers.js"; +import type { NftRestSchema } from "../../schema/rest.js"; +import type { + IsHolderOfContractParams, + IsHolderOfContractResult, +} from "../../types.js"; + +/** + * Checks whether a wallet holds any NFT from a contract. The network is resolved per + * request: an explicit `network` param wins, otherwise the client's + * configured network/chain applies. + * + * @param {DataClient} client A client configured with an Alchemy transport + * @param {IsHolderOfContractParams} params Wallet address, contract address, and optional network override + * @param {RequestOptions} [options] Per-request options (abort signal) + * @returns {Promise} The holder check result + */ +export async function isHolderOfContract( + client: DataClient, + params: IsHolderOfContractParams, + options?: RequestOptions, +): Promise { + const { network, ...query } = params; + const { slug } = resolveRequestNetwork(client, network); + const restClient = getRestClient(client, getNftApiUrl(slug)); + return restClient.request({ + route: "isHolderOfContract", + method: "GET", + query, + signal: options?.signal, + }); +} diff --git a/packages/data-apis/src/actions/nft/isSpamContract.ts b/packages/data-apis/src/actions/nft/isSpamContract.ts new file mode 100644 index 0000000000..efddcd46a7 --- /dev/null +++ b/packages/data-apis/src/actions/nft/isSpamContract.ts @@ -0,0 +1,38 @@ +import { getNftApiUrl } from "../../internal/endpoints.js"; +import { + getRestClient, + resolveRequestNetwork, + type DataClient, + type RequestOptions, +} from "../../internal/clientHelpers.js"; +import type { NftRestSchema } from "../../schema/rest.js"; +import type { + IsSpamContractParams, + IsSpamContractResult, +} from "../../types.js"; + +/** + * Checks whether a contract is classified as spam. The network is resolved per + * request: an explicit `network` param wins, otherwise the client's + * configured network/chain applies. + * + * @param {DataClient} client A client configured with an Alchemy transport + * @param {IsSpamContractParams} params Contract address and optional network override + * @param {RequestOptions} [options] Per-request options (abort signal) + * @returns {Promise} The spam classification + */ +export async function isSpamContract( + client: DataClient, + params: IsSpamContractParams, + options?: RequestOptions, +): Promise { + const { network, ...query } = params; + const { slug } = resolveRequestNetwork(client, network); + const restClient = getRestClient(client, getNftApiUrl(slug)); + return restClient.request({ + route: "isSpamContract", + method: "GET", + query, + signal: options?.signal, + }); +} diff --git a/packages/data-apis/src/actions/nft/nft.test.ts b/packages/data-apis/src/actions/nft/nft.test.ts new file mode 100644 index 0000000000..6a2ed6bfce --- /dev/null +++ b/packages/data-apis/src/actions/nft/nft.test.ts @@ -0,0 +1,175 @@ +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; +import { createDataClient } from "../../client.js"; + +const fetchMock = vi.fn(); + +const jsonResponse = (body: unknown) => + new Response(JSON.stringify(body), { + status: 200, + headers: { "Content-Type": "application/json" }, + }); + +const makeClient = () => + createDataClient({ apiKey: "test-key", network: "eth-mainnet" }); + +beforeEach(() => { + vi.stubGlobal("fetch", fetchMock); + fetchMock.mockReset(); + fetchMock.mockImplementation(async () => jsonResponse({})); +}); + +afterEach(() => { + vi.unstubAllGlobals(); +}); + +const NFT_BASE = "https://eth-mainnet.g.alchemy.com/nft/v3"; + +describe("nft namespace routing", () => { + // [method call, expected URL] — wire-level checks for the patterned GETs + const cases: Array< + [string, (c: ReturnType) => Promise, string] + > = [ + [ + "getNftsForContract", + (c) => c.nft.getNftsForContract({ contractAddress: "0xc" }), + `${NFT_BASE}/getNFTsForContract?contractAddress=0xc`, + ], + [ + "getNftsForCollection", + (c) => c.nft.getNftsForCollection({ collectionSlug: "slug" }), + `${NFT_BASE}/getNFTsForCollection?collectionSlug=slug`, + ], + [ + "getNftMetadata", + (c) => c.nft.getNftMetadata({ contractAddress: "0xc", tokenId: "1" }), + `${NFT_BASE}/getNFTMetadata?contractAddress=0xc&tokenId=1`, + ], + [ + "getContractMetadata", + (c) => c.nft.getContractMetadata({ contractAddress: "0xc" }), + `${NFT_BASE}/getContractMetadata?contractAddress=0xc`, + ], + [ + "getCollectionMetadata", + (c) => c.nft.getCollectionMetadata({ collectionSlug: "slug" }), + `${NFT_BASE}/getCollectionMetadata?collectionSlug=slug`, + ], + [ + "getOwnersForNft", + (c) => c.nft.getOwnersForNft({ contractAddress: "0xc", tokenId: "1" }), + `${NFT_BASE}/getOwnersForNFT?contractAddress=0xc&tokenId=1`, + ], + [ + "getOwnersForContract", + (c) => c.nft.getOwnersForContract({ contractAddress: "0xc" }), + `${NFT_BASE}/getOwnersForContract?contractAddress=0xc`, + ], + [ + "getNftSales", + (c) => c.nft.getNftSales({ contractAddress: "0xc", limit: 5 }), + `${NFT_BASE}/getNFTSales?contractAddress=0xc&limit=5`, + ], + [ + "getFloorPrice", + (c) => c.nft.getFloorPrice({ contractAddress: "0xc" }), + `${NFT_BASE}/getFloorPrice?contractAddress=0xc`, + ], + [ + "searchContractMetadata", + (c) => c.nft.searchContractMetadata({ query: "apes" }), + `${NFT_BASE}/searchContractMetadata?query=apes`, + ], + [ + "getSpamContracts", + (c) => c.nft.getSpamContracts(), + `${NFT_BASE}/getSpamContracts`, + ], + [ + "isSpamContract", + (c) => c.nft.isSpamContract({ contractAddress: "0xc" }), + `${NFT_BASE}/isSpamContract?contractAddress=0xc`, + ], + [ + "isAirdropNft", + (c) => c.nft.isAirdropNft({ contractAddress: "0xc", tokenId: "1" }), + `${NFT_BASE}/isAirdropNFT?contractAddress=0xc&tokenId=1`, + ], + [ + "isHolderOfContract", + (c) => + c.nft.isHolderOfContract({ wallet: "0xw", contractAddress: "0xc" }), + `${NFT_BASE}/isHolderOfContract?wallet=0xw&contractAddress=0xc`, + ], + [ + "computeRarity", + (c) => c.nft.computeRarity({ contractAddress: "0xc", tokenId: "1" }), + `${NFT_BASE}/computeRarity?contractAddress=0xc&tokenId=1`, + ], + [ + "summarizeNftAttributes", + (c) => c.nft.summarizeNftAttributes({ contractAddress: "0xc" }), + `${NFT_BASE}/summarizeNFTAttributes?contractAddress=0xc`, + ], + ]; + + it.each(cases)("%s hits the expected URL", async (_name, call, expected) => { + await call(makeClient()); + expect(String(fetchMock.mock.calls[0]![0])).toBe(expected); + expect(fetchMock.mock.calls[0]![1].method).toBe("GET"); + }); + + it("re-brackets filter keys for owner-scoped listings", async () => { + const data = makeClient(); + await data.nft.getContractsForOwner({ + owner: "0xo", + excludeFilters: ["SPAM"], + includeFilters: ["AIRDROPS"], + }); + const url = new URL(String(fetchMock.mock.calls[0]![0])); + expect(url.pathname.endsWith("/getContractsForOwner")).toBe(true); + expect(url.searchParams.getAll("excludeFilters[]")).toEqual(["SPAM"]); + expect(url.searchParams.getAll("includeFilters[]")).toEqual(["AIRDROPS"]); + + await data.nft.getCollectionsForOwner({ + owner: "0xo", + excludeFilters: ["SPAM"], + }); + const url2 = new URL(String(fetchMock.mock.calls[1]![0])); + expect(url2.searchParams.getAll("excludeFilters[]")).toEqual(["SPAM"]); + }); + + it("posts batch metadata bodies", async () => { + const data = makeClient(); + await data.nft.getNftMetadataBatch({ + tokens: [{ contractAddress: "0xc", tokenId: "1" }], + }); + expect(String(fetchMock.mock.calls[0]![0])).toBe( + `${NFT_BASE}/getNFTMetadataBatch`, + ); + expect(fetchMock.mock.calls[0]![1].method).toBe("POST"); + expect(JSON.parse(fetchMock.mock.calls[0]![1].body)).toEqual({ + tokens: [{ contractAddress: "0xc", tokenId: "1" }], + }); + + await data.nft.getContractMetadataBatch({ + contractAddresses: ["0xc1", "0xc2"], + }); + expect(String(fetchMock.mock.calls[1]![0])).toBe( + `${NFT_BASE}/getContractMetadataBatch`, + ); + expect(JSON.parse(fetchMock.mock.calls[1]![1].body)).toEqual({ + contractAddresses: ["0xc1", "0xc2"], + }); + }); + + it("honors per-request network overrides", async () => { + const data = makeClient(); + await data.nft.getContractMetadata({ + contractAddress: "0xc", + network: "base-mainnet", + }); + expect(String(fetchMock.mock.calls[0]![0])).toBe( + "https://base-mainnet.g.alchemy.com/nft/v3/getContractMetadata?contractAddress=0xc", + ); + }); +}); diff --git a/packages/data-apis/src/actions/nft/searchContractMetadata.ts b/packages/data-apis/src/actions/nft/searchContractMetadata.ts new file mode 100644 index 0000000000..2fe894274c --- /dev/null +++ b/packages/data-apis/src/actions/nft/searchContractMetadata.ts @@ -0,0 +1,38 @@ +import { getNftApiUrl } from "../../internal/endpoints.js"; +import { + getRestClient, + resolveRequestNetwork, + type DataClient, + type RequestOptions, +} from "../../internal/clientHelpers.js"; +import type { NftRestSchema } from "../../schema/rest.js"; +import type { + SearchContractMetadataParams, + SearchContractMetadataResult, +} from "../../types.js"; + +/** + * Searches NFT contract metadata by keyword. The network is resolved per + * request: an explicit `network` param wins, otherwise the client's + * configured network/chain applies. + * + * @param {DataClient} client A client configured with an Alchemy transport + * @param {SearchContractMetadataParams} params Search query and optional network override + * @param {RequestOptions} [options] Per-request options (abort signal) + * @returns {Promise} The matching contracts + */ +export async function searchContractMetadata( + client: DataClient, + params: SearchContractMetadataParams, + options?: RequestOptions, +): Promise { + const { network, ...query } = params; + const { slug } = resolveRequestNetwork(client, network); + const restClient = getRestClient(client, getNftApiUrl(slug)); + return restClient.request({ + route: "searchContractMetadata", + method: "GET", + query, + signal: options?.signal, + }); +} diff --git a/packages/data-apis/src/actions/nft/summarizeNftAttributes.ts b/packages/data-apis/src/actions/nft/summarizeNftAttributes.ts new file mode 100644 index 0000000000..057edaf64a --- /dev/null +++ b/packages/data-apis/src/actions/nft/summarizeNftAttributes.ts @@ -0,0 +1,38 @@ +import { getNftApiUrl } from "../../internal/endpoints.js"; +import { + getRestClient, + resolveRequestNetwork, + type DataClient, + type RequestOptions, +} from "../../internal/clientHelpers.js"; +import type { NftRestSchema } from "../../schema/rest.js"; +import type { + SummarizeNftAttributesParams, + SummarizeNftAttributesResult, +} from "../../types.js"; + +/** + * Summarizes attribute prevalence for an NFT contract. The network is resolved per + * request: an explicit `network` param wins, otherwise the client's + * configured network/chain applies. + * + * @param {DataClient} client A client configured with an Alchemy transport + * @param {SummarizeNftAttributesParams} params Contract address and optional network override + * @param {RequestOptions} [options] Per-request options (abort signal) + * @returns {Promise} The attribute summary + */ +export async function summarizeNftAttributes( + client: DataClient, + params: SummarizeNftAttributesParams, + options?: RequestOptions, +): Promise { + const { network, ...query } = params; + const { slug } = resolveRequestNetwork(client, network); + const restClient = getRestClient(client, getNftApiUrl(slug)); + return restClient.request({ + route: "summarizeNFTAttributes", + method: "GET", + query, + signal: options?.signal, + }); +} diff --git a/packages/data-apis/src/actions/portfolio/getNftContractsByAddress.ts b/packages/data-apis/src/actions/portfolio/getNftContractsByAddress.ts new file mode 100644 index 0000000000..1440eca92f --- /dev/null +++ b/packages/data-apis/src/actions/portfolio/getNftContractsByAddress.ts @@ -0,0 +1,47 @@ +import { resolveNetwork } from "@alchemy/common"; +import { DATA_API_URL } from "../../internal/endpoints.js"; +import { + getRestClient, + type DataClient, + type RequestOptions, +} from "../../internal/clientHelpers.js"; +import type { GetNftContractsByAddressBody } from "../../generated/rest/portfolio.schema.js"; +import type { PortfolioRestSchema } from "../../schema/rest.js"; +import type { + GetNftContractsByAddressParams, + GetNftContractsByAddressResult, +} from "../../types.js"; + +/** + * Fetches NFT contracts for one or more addresses across one or more + * networks in a single call. + * This is a multi-network request against the global Data API: networks + * travel in the request body, so the client's chain is not involved. + * + * @param {DataClient} client A client configured with an Alchemy transport + * @param {GetNftContractsByAddressParams} params Addresses paired with networks, plus options + * @param {RequestOptions} [options] Per-request options (abort signal) + * @returns {Promise} The owned NFT contracts and pagination cursor + */ +export async function getNftContractsByAddress( + client: DataClient, + params: GetNftContractsByAddressParams, + options?: RequestOptions, +): Promise { + const { addresses, ...rest } = params; + const restClient = getRestClient(client, DATA_API_URL); + return restClient.request({ + route: "assets/nfts/contracts/by-address", + method: "POST", + // The cast widens the spec's network-slug enum: the SDK deliberately + // accepts registry-unknown slugs as an escape hatch. + body: { + ...rest, + addresses: addresses.map(({ networks, ...entry }) => ({ + ...entry, + networks: networks.map((n) => resolveNetwork(n).slug), + })), + } as GetNftContractsByAddressBody, + signal: options?.signal, + }); +} diff --git a/packages/data-apis/src/actions/portfolio/getNftsByAddress.ts b/packages/data-apis/src/actions/portfolio/getNftsByAddress.ts new file mode 100644 index 0000000000..38c6c8cc52 --- /dev/null +++ b/packages/data-apis/src/actions/portfolio/getNftsByAddress.ts @@ -0,0 +1,47 @@ +import { resolveNetwork } from "@alchemy/common"; +import { DATA_API_URL } from "../../internal/endpoints.js"; +import { + getRestClient, + type DataClient, + type RequestOptions, +} from "../../internal/clientHelpers.js"; +import type { GetNftsByAddressBody } from "../../generated/rest/portfolio.schema.js"; +import type { PortfolioRestSchema } from "../../schema/rest.js"; +import type { + GetNftsByAddressParams, + GetNftsByAddressResult, +} from "../../types.js"; + +/** + * Fetches NFTs for one or more addresses across one or more networks in a + * single call. + * This is a multi-network request against the global Data API: networks + * travel in the request body, so the client's chain is not involved. + * + * @param {DataClient} client A client configured with an Alchemy transport + * @param {GetNftsByAddressParams} params Addresses paired with networks, plus options + * @param {RequestOptions} [options] Per-request options (abort signal) + * @returns {Promise} The owned NFTs and pagination cursor + */ +export async function getNftsByAddress( + client: DataClient, + params: GetNftsByAddressParams, + options?: RequestOptions, +): Promise { + const { addresses, ...rest } = params; + const restClient = getRestClient(client, DATA_API_URL); + return restClient.request({ + route: "assets/nfts/by-address", + method: "POST", + // The cast widens the spec's network-slug enum: the SDK deliberately + // accepts registry-unknown slugs as an escape hatch. + body: { + ...rest, + addresses: addresses.map(({ networks, ...entry }) => ({ + ...entry, + networks: networks.map((n) => resolveNetwork(n).slug), + })), + } as GetNftsByAddressBody, + signal: options?.signal, + }); +} diff --git a/packages/data-apis/src/actions/portfolio/getTokenBalancesByAddress.ts b/packages/data-apis/src/actions/portfolio/getTokenBalancesByAddress.ts new file mode 100644 index 0000000000..8c8acb89cc --- /dev/null +++ b/packages/data-apis/src/actions/portfolio/getTokenBalancesByAddress.ts @@ -0,0 +1,47 @@ +import { resolveNetwork } from "@alchemy/common"; +import { DATA_API_URL } from "../../internal/endpoints.js"; +import { + getRestClient, + type DataClient, + type RequestOptions, +} from "../../internal/clientHelpers.js"; +import type { GetTokenBalancesByAddressBody } from "../../generated/rest/portfolio.schema.js"; +import type { PortfolioRestSchema } from "../../schema/rest.js"; +import type { + GetTokenBalancesByAddressParams, + GetTokenBalancesByAddressResult, +} from "../../types.js"; + +/** + * Fetches token balances (without metadata or prices) for one or more + * addresses across one or more networks in a single call. + * This is a multi-network request against the global Data API: networks + * travel in the request body, so the client's chain is not involved. + * + * @param {DataClient} client A client configured with an Alchemy transport + * @param {GetTokenBalancesByAddressParams} params Addresses paired with networks, plus options + * @param {RequestOptions} [options] Per-request options (abort signal) + * @returns {Promise} Token balances per wallet/network pair + */ +export async function getTokenBalancesByAddress( + client: DataClient, + params: GetTokenBalancesByAddressParams, + options?: RequestOptions, +): Promise { + const { addresses, ...rest } = params; + const restClient = getRestClient(client, DATA_API_URL); + return restClient.request({ + route: "assets/tokens/balances/by-address", + method: "POST", + // The cast widens the spec's network-slug enum: the SDK deliberately + // accepts registry-unknown slugs as an escape hatch. + body: { + ...rest, + addresses: addresses.map(({ networks, ...entry }) => ({ + ...entry, + networks: networks.map((n) => resolveNetwork(n).slug), + })), + } as GetTokenBalancesByAddressBody, + signal: options?.signal, + }); +} diff --git a/packages/data-apis/src/actions/portfolio/getTokensByAddress.ts b/packages/data-apis/src/actions/portfolio/getTokensByAddress.ts index dde71c5bb0..c18bc31dc5 100644 --- a/packages/data-apis/src/actions/portfolio/getTokensByAddress.ts +++ b/packages/data-apis/src/actions/portfolio/getTokensByAddress.ts @@ -3,6 +3,7 @@ import { DATA_API_URL } from "../../internal/endpoints.js"; import { getRestClient, type DataClient, + type RequestOptions, } from "../../internal/clientHelpers.js"; import type { PortfolioRestSchema } from "../../schema/rest.js"; import type { @@ -27,23 +28,26 @@ import type { * * @param {DataClient} client A client configured with an Alchemy transport * @param {GetTokensByAddressParams} params Addresses paired with networks, plus options + * @param {RequestOptions} [options] Per-request options (abort signal) * @returns {Promise} Token balances, metadata, and prices */ export async function getTokensByAddress( client: DataClient, params: GetTokensByAddressParams, + options?: RequestOptions, ): Promise { - const { addresses, ...options } = params; + const { addresses, ...rest } = params; const restClient = getRestClient(client, DATA_API_URL); return restClient.request({ route: "assets/tokens/by-address", method: "POST", body: { - ...options, + ...rest, addresses: addresses.map(({ address, networks }) => ({ address, networks: networks.map((n) => resolveNetwork(n).slug), })), }, + signal: options?.signal, }); } diff --git a/packages/data-apis/src/actions/portfolio/portfolio.test.ts b/packages/data-apis/src/actions/portfolio/portfolio.test.ts new file mode 100644 index 0000000000..ad0765733f --- /dev/null +++ b/packages/data-apis/src/actions/portfolio/portfolio.test.ts @@ -0,0 +1,63 @@ +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; +import { createDataClient } from "../../client.js"; + +const fetchMock = vi.fn(); + +const jsonResponse = (body: unknown) => + new Response(JSON.stringify(body), { + status: 200, + headers: { "Content-Type": "application/json" }, + }); + +const makeClient = () => + createDataClient({ apiKey: "test-key", network: "eth-mainnet" }); + +beforeEach(() => { + vi.stubGlobal("fetch", fetchMock); + fetchMock.mockReset(); + fetchMock.mockImplementation(async () => jsonResponse({ data: {} })); +}); + +afterEach(() => { + vi.unstubAllGlobals(); +}); + +const DATA_BASE = "https://api.g.alchemy.com/data/v1"; + +describe("portfolio namespace", () => { + it.each([ + ["getTokenBalancesByAddress", "assets/tokens/balances/by-address"], + ["getNftsByAddress", "assets/nfts/by-address"], + ["getNftContractsByAddress", "assets/nfts/contracts/by-address"], + ] as const)("%s posts to the global Data API", async (method, route) => { + const data = makeClient(); + await data.portfolio[method]({ + addresses: [{ address: "0xa", networks: ["eth-mainnet", "eip155:8453"] }], + }); + expect(String(fetchMock.mock.calls[0]![0])).toBe(`${DATA_BASE}/${route}`); + expect(JSON.parse(fetchMock.mock.calls[0]![1].body)).toEqual({ + addresses: [ + { address: "0xa", networks: ["eth-mainnet", "base-mainnet"] }, + ], + }); + }); + + it("preserves per-entry fields beyond address/networks", async () => { + await makeClient().portfolio.getNftsByAddress({ + addresses: [ + { + address: "0xa", + networks: ["eth-mainnet"], + excludeFilters: ["SPAM"], + }, + ], + pageSize: 10, + }); + expect(JSON.parse(fetchMock.mock.calls[0]![1].body)).toEqual({ + addresses: [ + { address: "0xa", networks: ["eth-mainnet"], excludeFilters: ["SPAM"] }, + ], + pageSize: 10, + }); + }); +}); diff --git a/packages/data-apis/src/actions/prices/getHistoricalTokenPrices.ts b/packages/data-apis/src/actions/prices/getHistoricalTokenPrices.ts new file mode 100644 index 0000000000..dbba35e97e --- /dev/null +++ b/packages/data-apis/src/actions/prices/getHistoricalTokenPrices.ts @@ -0,0 +1,44 @@ +import { resolveNetwork } from "@alchemy/common"; +import { PRICES_API_URL } from "../../internal/endpoints.js"; +import { + getRestClient, + type DataClient, + type RequestOptions, +} from "../../internal/clientHelpers.js"; +import type { GetHistoricalTokenPricesBody } from "../../generated/rest/prices.schema.js"; +import type { PricesRestSchema } from "../../schema/rest.js"; +import type { + GetHistoricalTokenPricesParams, + GetHistoricalTokenPricesResult, +} from "../../types.js"; + +/** + * Fetches historical prices for a token, identified either by symbol + * (chain-agnostic) or by network + contract address. Runs against the global + * Prices API; when a network is given it travels in the request body, so the + * client's chain is not involved. + * + * @param {DataClient} client A client configured with an Alchemy transport + * @param {GetHistoricalTokenPricesParams} params Token identifier, time range, and interval + * @param {RequestOptions} [options] Per-request options (abort signal) + * @returns {Promise} The price series + */ +export async function getHistoricalTokenPrices( + client: DataClient, + params: GetHistoricalTokenPricesParams, + options?: RequestOptions, +): Promise { + const body = ( + "network" in params && params.network != null + ? { ...params, network: resolveNetwork(params.network).slug } + : params + ) as GetHistoricalTokenPricesBody; + + const restClient = getRestClient(client, PRICES_API_URL); + return restClient.request({ + route: "tokens/historical", + method: "POST", + body, + signal: options?.signal, + }); +} diff --git a/packages/data-apis/src/actions/prices/getTokenPricesByAddress.ts b/packages/data-apis/src/actions/prices/getTokenPricesByAddress.ts new file mode 100644 index 0000000000..47430f495d --- /dev/null +++ b/packages/data-apis/src/actions/prices/getTokenPricesByAddress.ts @@ -0,0 +1,41 @@ +import { resolveNetwork } from "@alchemy/common"; +import { PRICES_API_URL } from "../../internal/endpoints.js"; +import { + getRestClient, + type DataClient, + type RequestOptions, +} from "../../internal/clientHelpers.js"; +import type { PricesRestSchema } from "../../schema/rest.js"; +import type { + GetTokenPricesByAddressParams, + GetTokenPricesByAddressResult, +} from "../../types.js"; + +/** + * Fetches current prices for tokens by contract address (max 25 pairs). This + * is a multi-network request against the global Prices API: each entry pairs + * an address with its network, so the client's chain is not involved. + * + * @param {DataClient} client A client configured with an Alchemy transport + * @param {GetTokenPricesByAddressParams} params Address/network pairs to price + * @param {RequestOptions} [options] Per-request options (abort signal) + * @returns {Promise} Prices per address/network pair + */ +export async function getTokenPricesByAddress( + client: DataClient, + params: GetTokenPricesByAddressParams, + options?: RequestOptions, +): Promise { + const restClient = getRestClient(client, PRICES_API_URL); + return restClient.request({ + route: "tokens/by-address", + method: "POST", + body: { + addresses: params.addresses.map(({ address, network }) => ({ + address, + network: resolveNetwork(network).slug, + })), + }, + signal: options?.signal, + }); +} diff --git a/packages/data-apis/src/actions/prices/getTokenPricesBySymbol.ts b/packages/data-apis/src/actions/prices/getTokenPricesBySymbol.ts new file mode 100644 index 0000000000..a87955bc9f --- /dev/null +++ b/packages/data-apis/src/actions/prices/getTokenPricesBySymbol.ts @@ -0,0 +1,35 @@ +import { PRICES_API_URL } from "../../internal/endpoints.js"; +import { + getRestClient, + type DataClient, + type RequestOptions, +} from "../../internal/clientHelpers.js"; +import type { PricesRestSchema } from "../../schema/rest.js"; +import type { + GetTokenPricesBySymbolParams, + GetTokenPricesBySymbolResult, +} from "../../types.js"; + +/** + * Fetches current prices for tokens by symbol (max 25). This is a + * chain-agnostic request against the global Prices API — no network is + * involved at all. + * + * @param {DataClient} client A client configured with an Alchemy transport + * @param {GetTokenPricesBySymbolParams} params The token symbols to price + * @param {RequestOptions} [options] Per-request options (abort signal) + * @returns {Promise} Prices per symbol + */ +export async function getTokenPricesBySymbol( + client: DataClient, + params: GetTokenPricesBySymbolParams, + options?: RequestOptions, +): Promise { + const restClient = getRestClient(client, PRICES_API_URL); + return restClient.request({ + route: "tokens/by-symbol", + method: "GET", + query: params, + signal: options?.signal, + }); +} diff --git a/packages/data-apis/src/actions/prices/prices.test.ts b/packages/data-apis/src/actions/prices/prices.test.ts new file mode 100644 index 0000000000..3b6a82a4eb --- /dev/null +++ b/packages/data-apis/src/actions/prices/prices.test.ts @@ -0,0 +1,84 @@ +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; +import { mainnet } from "viem/chains"; +import { createDataClient } from "../../client.js"; + +const fetchMock = vi.fn(); + +const jsonResponse = (body: unknown) => + new Response(JSON.stringify(body), { + status: 200, + headers: { "Content-Type": "application/json" }, + }); + +const makeClient = () => + createDataClient({ apiKey: "test-key", network: "eth-mainnet" }); + +beforeEach(() => { + vi.stubGlobal("fetch", fetchMock); + fetchMock.mockReset(); + fetchMock.mockImplementation(async () => jsonResponse({ data: [] })); +}); + +afterEach(() => { + vi.unstubAllGlobals(); +}); + +const PRICES_BASE = "https://api.g.alchemy.com/prices/v1"; + +describe("prices namespace", () => { + it("by-symbol is a chain-agnostic GET with repeated symbols", async () => { + await makeClient().prices.getTokenPricesBySymbol({ + symbols: ["ETH", "USDC"], + }); + const url = new URL(String(fetchMock.mock.calls[0]![0])); + expect(`${url.origin}${url.pathname}`).toBe( + `${PRICES_BASE}/tokens/by-symbol`, + ); + expect(url.searchParams.getAll("symbols")).toEqual(["ETH", "USDC"]); + expect(fetchMock.mock.calls[0]![1].method).toBe("GET"); + }); + + it("by-address resolves each entry's network to a slug in the body", async () => { + await makeClient().prices.getTokenPricesByAddress({ + addresses: [ + { address: "0xa", network: mainnet }, + { address: "0xb", network: "eip155:8453" }, + { address: "0xc", network: "polygon-mainnet" }, + ], + }); + expect(String(fetchMock.mock.calls[0]![0])).toBe( + `${PRICES_BASE}/tokens/by-address`, + ); + expect(JSON.parse(fetchMock.mock.calls[0]![1].body)).toEqual({ + addresses: [ + { address: "0xa", network: "eth-mainnet" }, + { address: "0xb", network: "base-mainnet" }, + { address: "0xc", network: "polygon-mainnet" }, + ], + }); + }); + + it("historical accepts symbol form untouched and resolves network form", async () => { + const data = makeClient(); + await data.prices.getHistoricalTokenPrices({ + symbol: "ETH", + startTime: "2024-01-01T00:00:00Z", + endTime: "2024-01-02T00:00:00Z", + interval: "1h", + }); + expect(JSON.parse(fetchMock.mock.calls[0]![1].body).symbol).toBe("ETH"); + + await data.prices.getHistoricalTokenPrices({ + network: "eip155:1", + address: "0xa", + startTime: "2024-01-01T00:00:00Z", + endTime: "2024-01-02T00:00:00Z", + interval: "1d", + }); + const body = JSON.parse(fetchMock.mock.calls[1]![1].body); + expect(body.network).toBe("eth-mainnet"); + expect(String(fetchMock.mock.calls[1]![0])).toBe( + `${PRICES_BASE}/tokens/historical`, + ); + }); +}); diff --git a/packages/data-apis/src/actions/token/getTokenAllowance.ts b/packages/data-apis/src/actions/token/getTokenAllowance.ts new file mode 100644 index 0000000000..67cb94315d --- /dev/null +++ b/packages/data-apis/src/actions/token/getTokenAllowance.ts @@ -0,0 +1,30 @@ +import { + getRpcRequest, + type DataClient, +} from "../../internal/clientHelpers.js"; +import type { + GetTokenAllowanceParams, + GetTokenAllowanceResult, +} from "../../types.js"; + +/** + * Fetches the ERC-20 allowance a spender has from an owner via the + * `alchemy_getTokenAllowance` JSON-RPC method. Without a `network` override + * this uses the client's transport; with one, a transport instance is derived + * for the override network. + * + * @param {DataClient} client A client configured with an Alchemy transport + * @param {GetTokenAllowanceParams} params Contract, owner, spender, and optional network override + * @returns {Promise} The allowance as a decimal string + */ +export async function getTokenAllowance( + client: DataClient, + params: GetTokenAllowanceParams, +): Promise { + const { network, ...allowanceRequest } = params; + const request = getRpcRequest(client, network); + return request({ + method: "alchemy_getTokenAllowance", + params: [allowanceRequest], + }); +} diff --git a/packages/data-apis/src/actions/token/getTokenBalances.ts b/packages/data-apis/src/actions/token/getTokenBalances.ts new file mode 100644 index 0000000000..c303ef7742 --- /dev/null +++ b/packages/data-apis/src/actions/token/getTokenBalances.ts @@ -0,0 +1,42 @@ +import { + getRpcRequest, + type DataClient, +} from "../../internal/clientHelpers.js"; +import type { TokenRpcSchema } from "../../generated/rpc/token.js"; +import type { + GetTokenBalancesParams, + GetTokenBalancesResult, +} from "../../types.js"; + +/** + * Fetches ERC-20 (and native) token balances for an address via the + * `alchemy_getTokenBalances` JSON-RPC method. Without a `network` override + * this uses the client's transport; with one, a transport instance is derived + * for the override network. + * + * @param {DataClient} client A client configured with an Alchemy transport + * @param {GetTokenBalancesParams} params Address, token spec, paging options, and optional network override + * @returns {Promise} The token balances + */ +export async function getTokenBalances( + client: DataClient, + params: GetTokenBalancesParams, +): Promise { + const { network, address, tokenSpec, options } = params; + const request = getRpcRequest(client, network); + + // Positional JSON-RPC params; trailing optionals are omitted when unset. + // "erc20" is the spec's default tokenSpec, filled in only when paging + // options are supplied without one. + const rpcParams: TokenRpcSchema[0]["Parameters"] = + options !== undefined + ? [address, tokenSpec ?? "erc20", options] + : tokenSpec !== undefined + ? [address, tokenSpec] + : [address]; + + return request({ + method: "alchemy_getTokenBalances", + params: rpcParams, + }); +} diff --git a/packages/data-apis/src/actions/token/getTokenMetadata.ts b/packages/data-apis/src/actions/token/getTokenMetadata.ts new file mode 100644 index 0000000000..7b9593fad4 --- /dev/null +++ b/packages/data-apis/src/actions/token/getTokenMetadata.ts @@ -0,0 +1,30 @@ +import { + getRpcRequest, + type DataClient, +} from "../../internal/clientHelpers.js"; +import type { + GetTokenMetadataParams, + GetTokenMetadataResult, +} from "../../types.js"; + +/** + * Fetches metadata (name, symbol, decimals, logo) for a token contract via + * the `alchemy_getTokenMetadata` JSON-RPC method. Without a `network` + * override this uses the client's transport; with one, a transport instance + * is derived for the override network. + * + * @param {DataClient} client A client configured with an Alchemy transport + * @param {GetTokenMetadataParams} params The contract address and optional network override + * @returns {Promise} The token metadata + */ +export async function getTokenMetadata( + client: DataClient, + params: GetTokenMetadataParams, +): Promise { + const { network, contractAddress } = params; + const request = getRpcRequest(client, network); + return request({ + method: "alchemy_getTokenMetadata", + params: [contractAddress], + }); +} diff --git a/packages/data-apis/src/actions/token/token.test.ts b/packages/data-apis/src/actions/token/token.test.ts new file mode 100644 index 0000000000..58c3c5a9ce --- /dev/null +++ b/packages/data-apis/src/actions/token/token.test.ts @@ -0,0 +1,76 @@ +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; +import { createDataClient } from "../../client.js"; + +const fetchMock = vi.fn(); + +const rpcResponse = (result: unknown) => + new Response(JSON.stringify({ jsonrpc: "2.0", id: 1, result }), { + status: 200, + headers: { "Content-Type": "application/json" }, + }); + +const makeClient = () => + createDataClient({ apiKey: "test-key", network: "eth-mainnet" }); + +beforeEach(() => { + vi.stubGlobal("fetch", fetchMock); + fetchMock.mockReset(); + fetchMock.mockImplementation(async () => rpcResponse({})); +}); + +afterEach(() => { + vi.unstubAllGlobals(); +}); + +const rpcBody = (call: number) => + JSON.parse(fetchMock.mock.calls[call]![1].body); + +describe("token namespace", () => { + it("getTokenBalances sends positional params, omitting unset trailing optionals", async () => { + const data = makeClient(); + await data.token.getTokenBalances({ address: "0xa" }); + expect(rpcBody(0).method).toBe("alchemy_getTokenBalances"); + expect(rpcBody(0).params).toEqual(["0xa"]); + + await data.token.getTokenBalances({ address: "0xa", tokenSpec: "erc20" }); + expect(rpcBody(1).params).toEqual(["0xa", "erc20"]); + + await data.token.getTokenBalances({ + address: "0xa", + options: { pageKey: "next", maxCount: 10 }, + }); + // tokenSpec defaults to "erc20" when paging options are supplied alone + expect(rpcBody(2).params).toEqual([ + "0xa", + "erc20", + { pageKey: "next", maxCount: 10 }, + ]); + }); + + it("getTokenMetadata and getTokenAllowance send spec-shaped params", async () => { + const data = makeClient(); + await data.token.getTokenMetadata({ contractAddress: "0xc" }); + expect(rpcBody(0).method).toBe("alchemy_getTokenMetadata"); + expect(rpcBody(0).params).toEqual(["0xc"]); + + await data.token.getTokenAllowance({ + contract: "0xc", + owner: "0xo", + spender: "0xs", + }); + expect(rpcBody(1).method).toBe("alchemy_getTokenAllowance"); + expect(rpcBody(1).params).toEqual([ + { contract: "0xc", owner: "0xo", spender: "0xs" }, + ]); + }); + + it("honors per-request network overrides", async () => { + await makeClient().token.getTokenMetadata({ + contractAddress: "0xc", + network: "arb-mainnet", + }); + expect(String(fetchMock.mock.calls[0]![0])).toContain( + "https://arb-mainnet.g.alchemy.com/v2", + ); + }); +}); diff --git a/packages/data-apis/src/actions/transfers/getAssetTransfers.ts b/packages/data-apis/src/actions/transfers/getAssetTransfers.ts index f1726e9987..796edad0ab 100644 --- a/packages/data-apis/src/actions/transfers/getAssetTransfers.ts +++ b/packages/data-apis/src/actions/transfers/getAssetTransfers.ts @@ -1,16 +1,11 @@ -import { alchemyTransport } from "@alchemy/common"; -import { getRpcUrl } from "../../internal/endpoints.js"; import { - getTransportConfig, - resolveRequestNetwork, + getRpcRequest, type DataClient, } from "../../internal/clientHelpers.js"; -import type { DataRpcSchema } from "../../schema/rpc.js"; import type { GetAssetTransfersParams, GetAssetTransfersResult, } from "../../types.js"; -import type { EIP1193RequestFn } from "viem"; /** * Fetches historical asset transfers (external, internal, token) for the @@ -30,19 +25,7 @@ export async function getAssetTransfers( params: GetAssetTransfersParams, ): Promise { const { network, ...rpcParams } = params; - - const request = (() => { - if (!network) { - return client.request as EIP1193RequestFn; - } - const { slug } = resolveRequestNetwork(client, network); - const derived = alchemyTransport({ - ...getTransportConfig(client), - url: getRpcUrl(slug), - })({ retryCount: 0 }); - return derived.request as EIP1193RequestFn; - })(); - + const request = getRpcRequest(client, network); return request({ method: "alchemy_getAssetTransfers", params: [rpcParams], diff --git a/packages/data-apis/src/decorator.ts b/packages/data-apis/src/decorator.ts index 27e98ad87d..2d736cc9f5 100644 --- a/packages/data-apis/src/decorator.ts +++ b/packages/data-apis/src/decorator.ts @@ -1,32 +1,165 @@ -import type { - GetAssetTransfersParams, - GetAssetTransfersResult, - GetNftsForOwnerParams, - GetNftsForOwnerResult, - GetTokensByAddressParams, - GetTokensByAddressResult, -} from "./types.js"; -import type { DataClient } from "./internal/clientHelpers.js"; +import type { DataClient, RequestOptions } from "./internal/clientHelpers.js"; +import type * as T from "./types.js"; + import { getTokensByAddress } from "./actions/portfolio/getTokensByAddress.js"; +import { getTokenBalancesByAddress } from "./actions/portfolio/getTokenBalancesByAddress.js"; +import { getNftsByAddress } from "./actions/portfolio/getNftsByAddress.js"; +import { getNftContractsByAddress } from "./actions/portfolio/getNftContractsByAddress.js"; + +import { getTokenPricesBySymbol } from "./actions/prices/getTokenPricesBySymbol.js"; +import { getTokenPricesByAddress } from "./actions/prices/getTokenPricesByAddress.js"; +import { getHistoricalTokenPrices } from "./actions/prices/getHistoricalTokenPrices.js"; + import { getNftsForOwner } from "./actions/nft/getNftsForOwner.js"; +import { getNftsForContract } from "./actions/nft/getNftsForContract.js"; +import { getNftsForCollection } from "./actions/nft/getNftsForCollection.js"; +import { getNftMetadata } from "./actions/nft/getNftMetadata.js"; +import { getNftMetadataBatch } from "./actions/nft/getNftMetadataBatch.js"; +import { getContractMetadata } from "./actions/nft/getContractMetadata.js"; +import { getContractMetadataBatch } from "./actions/nft/getContractMetadataBatch.js"; +import { getCollectionMetadata } from "./actions/nft/getCollectionMetadata.js"; +import { getContractsForOwner } from "./actions/nft/getContractsForOwner.js"; +import { getCollectionsForOwner } from "./actions/nft/getCollectionsForOwner.js"; +import { getOwnersForNft } from "./actions/nft/getOwnersForNft.js"; +import { getOwnersForContract } from "./actions/nft/getOwnersForContract.js"; +import { getNftSales } from "./actions/nft/getNftSales.js"; +import { getFloorPrice } from "./actions/nft/getFloorPrice.js"; +import { searchContractMetadata } from "./actions/nft/searchContractMetadata.js"; +import { getSpamContracts } from "./actions/nft/getSpamContracts.js"; +import { isSpamContract } from "./actions/nft/isSpamContract.js"; +import { isAirdropNft } from "./actions/nft/isAirdropNft.js"; +import { isHolderOfContract } from "./actions/nft/isHolderOfContract.js"; +import { computeRarity } from "./actions/nft/computeRarity.js"; +import { summarizeNftAttributes } from "./actions/nft/summarizeNftAttributes.js"; + +import { getTokenBalances } from "./actions/token/getTokenBalances.js"; +import { getTokenMetadata } from "./actions/token/getTokenMetadata.js"; +import { getTokenAllowance } from "./actions/token/getTokenAllowance.js"; + import { getAssetTransfers } from "./actions/transfers/getAssetTransfers.js"; +type Action = ( + params: Params, + options?: RequestOptions, +) => Promise; + +type RpcAction = (params: Params) => Promise; + /** The namespaced Data API actions attached by the {@link dataActions} decorator. */ export type DataActions = { portfolio: { - getTokensByAddress: ( - params: GetTokensByAddressParams, - ) => Promise; + getTokensByAddress: Action< + T.GetTokensByAddressParams, + T.GetTokensByAddressResult + >; + getTokenBalancesByAddress: Action< + T.GetTokenBalancesByAddressParams, + T.GetTokenBalancesByAddressResult + >; + getNftsByAddress: Action< + T.GetNftsByAddressParams, + T.GetNftsByAddressResult + >; + getNftContractsByAddress: Action< + T.GetNftContractsByAddressParams, + T.GetNftContractsByAddressResult + >; + }; + prices: { + getTokenPricesBySymbol: Action< + T.GetTokenPricesBySymbolParams, + T.GetTokenPricesBySymbolResult + >; + getTokenPricesByAddress: Action< + T.GetTokenPricesByAddressParams, + T.GetTokenPricesByAddressResult + >; + getHistoricalTokenPrices: Action< + T.GetHistoricalTokenPricesParams, + T.GetHistoricalTokenPricesResult + >; }; nft: { - getNftsForOwner: ( - params: GetNftsForOwnerParams, - ) => Promise; + getNftsForOwner: Action; + getNftsForContract: Action< + T.GetNftsForContractParams, + T.GetNftsForContractResult + >; + getNftsForCollection: Action< + T.GetNftsForCollectionParams, + T.GetNftsForCollectionResult + >; + getNftMetadata: Action; + getNftMetadataBatch: Action< + T.GetNftMetadataBatchParams, + T.GetNftMetadataBatchResult + >; + getContractMetadata: Action< + T.GetContractMetadataParams, + T.GetContractMetadataResult + >; + getContractMetadataBatch: Action< + T.GetContractMetadataBatchParams, + T.GetContractMetadataBatchResult + >; + getCollectionMetadata: Action< + T.GetCollectionMetadataParams, + T.GetCollectionMetadataResult + >; + getContractsForOwner: Action< + T.GetContractsForOwnerParams, + T.GetContractsForOwnerResult + >; + getCollectionsForOwner: Action< + T.GetCollectionsForOwnerParams, + T.GetCollectionsForOwnerResult + >; + getOwnersForNft: Action; + getOwnersForContract: Action< + T.GetOwnersForContractParams, + T.GetOwnersForContractResult + >; + getNftSales: Action; + getFloorPrice: Action; + searchContractMetadata: Action< + T.SearchContractMetadataParams, + T.SearchContractMetadataResult + >; + getSpamContracts: Action< + T.GetSpamContractsParams, + T.GetSpamContractsResult + >; + isSpamContract: Action; + isAirdropNft: Action; + isHolderOfContract: Action< + T.IsHolderOfContractParams, + T.IsHolderOfContractResult + >; + computeRarity: Action; + summarizeNftAttributes: Action< + T.SummarizeNftAttributesParams, + T.SummarizeNftAttributesResult + >; + }; + token: { + getTokenBalances: RpcAction< + T.GetTokenBalancesParams, + T.GetTokenBalancesResult + >; + getTokenMetadata: RpcAction< + T.GetTokenMetadataParams, + T.GetTokenMetadataResult + >; + getTokenAllowance: RpcAction< + T.GetTokenAllowanceParams, + T.GetTokenAllowanceResult + >; }; transfers: { - getAssetTransfers: ( - params: GetAssetTransfersParams, - ) => Promise; + getAssetTransfers: RpcAction< + T.GetAssetTransfersParams, + T.GetAssetTransfersResult + >; }; }; @@ -55,10 +188,69 @@ export type DataActions = { export function dataActions(client: DataClient): DataActions { return { portfolio: { - getTokensByAddress: (params) => getTokensByAddress(client, params), + getTokensByAddress: (params, options) => + getTokensByAddress(client, params, options), + getTokenBalancesByAddress: (params, options) => + getTokenBalancesByAddress(client, params, options), + getNftsByAddress: (params, options) => + getNftsByAddress(client, params, options), + getNftContractsByAddress: (params, options) => + getNftContractsByAddress(client, params, options), + }, + prices: { + getTokenPricesBySymbol: (params, options) => + getTokenPricesBySymbol(client, params, options), + getTokenPricesByAddress: (params, options) => + getTokenPricesByAddress(client, params, options), + getHistoricalTokenPrices: (params, options) => + getHistoricalTokenPrices(client, params, options), }, nft: { - getNftsForOwner: (params) => getNftsForOwner(client, params), + getNftsForOwner: (params, options) => + getNftsForOwner(client, params, options), + getNftsForContract: (params, options) => + getNftsForContract(client, params, options), + getNftsForCollection: (params, options) => + getNftsForCollection(client, params, options), + getNftMetadata: (params, options) => + getNftMetadata(client, params, options), + getNftMetadataBatch: (params, options) => + getNftMetadataBatch(client, params, options), + getContractMetadata: (params, options) => + getContractMetadata(client, params, options), + getContractMetadataBatch: (params, options) => + getContractMetadataBatch(client, params, options), + getCollectionMetadata: (params, options) => + getCollectionMetadata(client, params, options), + getContractsForOwner: (params, options) => + getContractsForOwner(client, params, options), + getCollectionsForOwner: (params, options) => + getCollectionsForOwner(client, params, options), + getOwnersForNft: (params, options) => + getOwnersForNft(client, params, options), + getOwnersForContract: (params, options) => + getOwnersForContract(client, params, options), + getNftSales: (params, options) => getNftSales(client, params, options), + getFloorPrice: (params, options) => + getFloorPrice(client, params, options), + searchContractMetadata: (params, options) => + searchContractMetadata(client, params, options), + getSpamContracts: (params, options) => + getSpamContracts(client, params, options), + isSpamContract: (params, options) => + isSpamContract(client, params, options), + isAirdropNft: (params, options) => isAirdropNft(client, params, options), + isHolderOfContract: (params, options) => + isHolderOfContract(client, params, options), + computeRarity: (params, options) => + computeRarity(client, params, options), + summarizeNftAttributes: (params, options) => + summarizeNftAttributes(client, params, options), + }, + token: { + getTokenBalances: (params) => getTokenBalances(client, params), + getTokenMetadata: (params) => getTokenMetadata(client, params), + getTokenAllowance: (params) => getTokenAllowance(client, params), }, transfers: { getAssetTransfers: (params) => getAssetTransfers(client, params), diff --git a/packages/data-apis/src/generated/rest/nft.schema.ts b/packages/data-apis/src/generated/rest/nft.schema.ts index c52bf3c614..624b45287b 100644 --- a/packages/data-apis/src/generated/rest/nft.schema.ts +++ b/packages/data-apis/src/generated/rest/nft.schema.ts @@ -15,6 +15,181 @@ export type GetNftsForOwnerQuery = NonNullable< operations["getNFTsForOwner-v3"]["parameters"]["query"] >; +/** 200 response for getNFTsForContract-v3. */ +export type GetNftsForContractResponse = + operations["getNFTsForContract-v3"]["responses"]["200"]["content"]["application/json"]; + +/** Query params for getNFTsForContract-v3. */ +export type GetNftsForContractQuery = NonNullable< + operations["getNFTsForContract-v3"]["parameters"]["query"] +>; + +/** 200 response for getNFTsForCollection-v3. */ +export type GetNftsForCollectionResponse = + operations["getNFTsForCollection-v3"]["responses"]["200"]["content"]["application/json"]; + +/** Query params for getNFTsForCollection-v3. */ +export type GetNftsForCollectionQuery = NonNullable< + operations["getNFTsForCollection-v3"]["parameters"]["query"] +>; + +/** 200 response for getNFTMetadata-v3. */ +export type GetNftMetadataResponse = + operations["getNFTMetadata-v3"]["responses"]["200"]["content"]["application/json"]; + +/** Query params for getNFTMetadata-v3. */ +export type GetNftMetadataQuery = NonNullable< + operations["getNFTMetadata-v3"]["parameters"]["query"] +>; + +/** Request body for getNFTMetadataBatch-v3. */ +export type GetNftMetadataBatchBody = NonNullable< + operations["getNFTMetadataBatch-v3"]["requestBody"] +>["content"]["application/json"]; + +/** 200 response for getNFTMetadataBatch-v3. */ +export type GetNftMetadataBatchResponse = + operations["getNFTMetadataBatch-v3"]["responses"]["200"]["content"]["application/json"]; + +/** 200 response for getContractMetadata-v3. */ +export type GetContractMetadataResponse = + operations["getContractMetadata-v3"]["responses"]["200"]["content"]["application/json"]; + +/** Query params for getContractMetadata-v3. */ +export type GetContractMetadataQuery = NonNullable< + operations["getContractMetadata-v3"]["parameters"]["query"] +>; + +/** Request body for getContractMetadataBatch-v3. */ +export type GetContractMetadataBatchBody = NonNullable< + operations["getContractMetadataBatch-v3"]["requestBody"] +>["content"]["application/json"]; + +/** 200 response for getContractMetadataBatch-v3. */ +export type GetContractMetadataBatchResponse = + operations["getContractMetadataBatch-v3"]["responses"]["200"]["content"]["application/json"]; + +/** 200 response for getCollectionMetadata-v3. */ +export type GetCollectionMetadataResponse = + operations["getCollectionMetadata-v3"]["responses"]["200"]["content"]["application/json"]; + +/** Query params for getCollectionMetadata-v3. */ +export type GetCollectionMetadataQuery = NonNullable< + operations["getCollectionMetadata-v3"]["parameters"]["query"] +>; + +/** 200 response for getContractsForOwner-v3. */ +export type GetContractsForOwnerResponse = + operations["getContractsForOwner-v3"]["responses"]["200"]["content"]["application/json"]; + +/** Query params for getContractsForOwner-v3. */ +export type GetContractsForOwnerQuery = NonNullable< + operations["getContractsForOwner-v3"]["parameters"]["query"] +>; + +/** 200 response for getCollectionsForOwner-v3. */ +export type GetCollectionsForOwnerResponse = + operations["getCollectionsForOwner-v3"]["responses"]["200"]["content"]["application/json"]; + +/** Query params for getCollectionsForOwner-v3. */ +export type GetCollectionsForOwnerQuery = NonNullable< + operations["getCollectionsForOwner-v3"]["parameters"]["query"] +>; + +/** 200 response for getOwnersForNFT-v3. */ +export type GetOwnersForNftResponse = + operations["getOwnersForNFT-v3"]["responses"]["200"]["content"]["application/json"]; + +/** Query params for getOwnersForNFT-v3. */ +export type GetOwnersForNftQuery = NonNullable< + operations["getOwnersForNFT-v3"]["parameters"]["query"] +>; + +/** 200 response for getOwnersForContract-v3. */ +export type GetOwnersForContractResponse = + operations["getOwnersForContract-v3"]["responses"]["200"]["content"]["application/json"]; + +/** Query params for getOwnersForContract-v3. */ +export type GetOwnersForContractQuery = NonNullable< + operations["getOwnersForContract-v3"]["parameters"]["query"] +>; + +/** 200 response for getNFTSales-v3. */ +export type GetNftSalesResponse = + operations["getNFTSales-v3"]["responses"]["200"]["content"]["application/json"]; + +/** Query params for getNFTSales-v3. */ +export type GetNftSalesQuery = NonNullable< + operations["getNFTSales-v3"]["parameters"]["query"] +>; + +/** 200 response for getFloorPrice-v3. */ +export type GetFloorPriceResponse = + operations["getFloorPrice-v3"]["responses"]["200"]["content"]["application/json"]; + +/** Query params for getFloorPrice-v3. */ +export type GetFloorPriceQuery = NonNullable< + operations["getFloorPrice-v3"]["parameters"]["query"] +>; + +/** 200 response for searchContractMetadata-v3. */ +export type SearchContractMetadataResponse = + operations["searchContractMetadata-v3"]["responses"]["200"]["content"]["application/json"]; + +/** Query params for searchContractMetadata-v3. */ +export type SearchContractMetadataQuery = NonNullable< + operations["searchContractMetadata-v3"]["parameters"]["query"] +>; + +/** 200 response for getSpamContracts-v3. */ +export type GetSpamContractsResponse = + operations["getSpamContracts-v3"]["responses"]["200"]["content"]["application/json"]; + +/** 200 response for isSpamContract-v3. */ +export type IsSpamContractResponse = + operations["isSpamContract-v3"]["responses"]["200"]["content"]["application/json"]; + +/** Query params for isSpamContract-v3. */ +export type IsSpamContractQuery = NonNullable< + operations["isSpamContract-v3"]["parameters"]["query"] +>; + +/** 200 response for isAirdropNFT-v3. */ +export type IsAirdropNftResponse = + operations["isAirdropNFT-v3"]["responses"]["200"]["content"]["application/json"]; + +/** Query params for isAirdropNFT-v3. */ +export type IsAirdropNftQuery = NonNullable< + operations["isAirdropNFT-v3"]["parameters"]["query"] +>; + +/** 200 response for isHolderOfContract-v3. */ +export type IsHolderOfContractResponse = + operations["isHolderOfContract-v3"]["responses"]["200"]["content"]["application/json"]; + +/** Query params for isHolderOfContract-v3. */ +export type IsHolderOfContractQuery = NonNullable< + operations["isHolderOfContract-v3"]["parameters"]["query"] +>; + +/** 200 response for computeRarity-v3. */ +export type ComputeRarityResponse = + operations["computeRarity-v3"]["responses"]["200"]["content"]["application/json"]; + +/** Query params for computeRarity-v3. */ +export type ComputeRarityQuery = NonNullable< + operations["computeRarity-v3"]["parameters"]["query"] +>; + +/** 200 response for summarizeNFTAttributes-v3. */ +export type SummarizeNftAttributesResponse = + operations["summarizeNFTAttributes-v3"]["responses"]["200"]["content"]["application/json"]; + +/** Query params for summarizeNFTAttributes-v3. */ +export type SummarizeNftAttributesQuery = NonNullable< + operations["summarizeNFTAttributes-v3"]["parameters"]["query"] +>; + /** RestRequestSchema entries for the nft REST API. */ export type NftRestSchema = readonly [ { @@ -25,6 +200,166 @@ export type NftRestSchema = readonly [ Query: GetNftsForOwnerQuery; Response: GetNftsForOwnerResponse; }, + { + /** GET /v3/{apiKey}/getNFTsForContract (operationId: getNFTsForContract-v3) */ + Route: "getNFTsForContract"; + Method: "GET"; + Body?: undefined; + Query: GetNftsForContractQuery; + Response: GetNftsForContractResponse; + }, + { + /** GET /v3/{apiKey}/getNFTsForCollection (operationId: getNFTsForCollection-v3) */ + Route: "getNFTsForCollection"; + Method: "GET"; + Body?: undefined; + Query?: GetNftsForCollectionQuery | undefined; + Response: GetNftsForCollectionResponse; + }, + { + /** GET /v3/{apiKey}/getNFTMetadata (operationId: getNFTMetadata-v3) */ + Route: "getNFTMetadata"; + Method: "GET"; + Body?: undefined; + Query: GetNftMetadataQuery; + Response: GetNftMetadataResponse; + }, + { + /** POST /v3/{apiKey}/getNFTMetadataBatch (operationId: getNFTMetadataBatch-v3) */ + Route: "getNFTMetadataBatch"; + Method: "POST"; + Body: GetNftMetadataBatchBody; + Query?: undefined; + Response: GetNftMetadataBatchResponse; + }, + { + /** GET /v3/{apiKey}/getContractMetadata (operationId: getContractMetadata-v3) */ + Route: "getContractMetadata"; + Method: "GET"; + Body?: undefined; + Query: GetContractMetadataQuery; + Response: GetContractMetadataResponse; + }, + { + /** POST /v3/{apiKey}/getContractMetadataBatch (operationId: getContractMetadataBatch-v3) */ + Route: "getContractMetadataBatch"; + Method: "POST"; + Body: GetContractMetadataBatchBody; + Query?: undefined; + Response: GetContractMetadataBatchResponse; + }, + { + /** GET /v3/{apiKey}/getCollectionMetadata (operationId: getCollectionMetadata-v3) */ + Route: "getCollectionMetadata"; + Method: "GET"; + Body?: undefined; + Query: GetCollectionMetadataQuery; + Response: GetCollectionMetadataResponse; + }, + { + /** GET /v3/{apiKey}/getContractsForOwner (operationId: getContractsForOwner-v3) */ + Route: "getContractsForOwner"; + Method: "GET"; + Body?: undefined; + Query: GetContractsForOwnerQuery; + Response: GetContractsForOwnerResponse; + }, + { + /** GET /v3/{apiKey}/getCollectionsForOwner (operationId: getCollectionsForOwner-v3) */ + Route: "getCollectionsForOwner"; + Method: "GET"; + Body?: undefined; + Query: GetCollectionsForOwnerQuery; + Response: GetCollectionsForOwnerResponse; + }, + { + /** GET /v3/{apiKey}/getOwnersForNFT (operationId: getOwnersForNFT-v3) */ + Route: "getOwnersForNFT"; + Method: "GET"; + Body?: undefined; + Query: GetOwnersForNftQuery; + Response: GetOwnersForNftResponse; + }, + { + /** GET /v3/{apiKey}/getOwnersForContract (operationId: getOwnersForContract-v3) */ + Route: "getOwnersForContract"; + Method: "GET"; + Body?: undefined; + Query: GetOwnersForContractQuery; + Response: GetOwnersForContractResponse; + }, + { + /** GET /v3/{apiKey}/getNFTSales (operationId: getNFTSales-v3) */ + Route: "getNFTSales"; + Method: "GET"; + Body?: undefined; + Query?: GetNftSalesQuery | undefined; + Response: GetNftSalesResponse; + }, + { + /** GET /v3/{apiKey}/getFloorPrice (operationId: getFloorPrice-v3) */ + Route: "getFloorPrice"; + Method: "GET"; + Body?: undefined; + Query: GetFloorPriceQuery; + Response: GetFloorPriceResponse; + }, + { + /** GET /v3/{apiKey}/searchContractMetadata (operationId: searchContractMetadata-v3) */ + Route: "searchContractMetadata"; + Method: "GET"; + Body?: undefined; + Query: SearchContractMetadataQuery; + Response: SearchContractMetadataResponse; + }, + { + /** GET /v3/{apiKey}/getSpamContracts (operationId: getSpamContracts-v3) */ + Route: "getSpamContracts"; + Method: "GET"; + Body?: undefined; + Query?: undefined; + Response: GetSpamContractsResponse; + }, + { + /** GET /v3/{apiKey}/isSpamContract (operationId: isSpamContract-v3) */ + Route: "isSpamContract"; + Method: "GET"; + Body?: undefined; + Query: IsSpamContractQuery; + Response: IsSpamContractResponse; + }, + { + /** GET /v3/{apiKey}/isAirdropNFT (operationId: isAirdropNFT-v3) */ + Route: "isAirdropNFT"; + Method: "GET"; + Body?: undefined; + Query: IsAirdropNftQuery; + Response: IsAirdropNftResponse; + }, + { + /** GET /v3/{apiKey}/isHolderOfContract (operationId: isHolderOfContract-v3) */ + Route: "isHolderOfContract"; + Method: "GET"; + Body?: undefined; + Query: IsHolderOfContractQuery; + Response: IsHolderOfContractResponse; + }, + { + /** GET /v3/{apiKey}/computeRarity (operationId: computeRarity-v3) */ + Route: "computeRarity"; + Method: "GET"; + Body?: undefined; + Query: ComputeRarityQuery; + Response: ComputeRarityResponse; + }, + { + /** GET /v3/{apiKey}/summarizeNFTAttributes (operationId: summarizeNFTAttributes-v3) */ + Route: "summarizeNFTAttributes"; + Method: "GET"; + Body?: undefined; + Query: SummarizeNftAttributesQuery; + Response: SummarizeNftAttributesResponse; + }, ]; /** Compile-time guard that the emitted tuple satisfies the shared constraint. */ diff --git a/packages/data-apis/src/generated/rest/portfolio.schema.ts b/packages/data-apis/src/generated/rest/portfolio.schema.ts index a2860547d4..3bfdc519b7 100644 --- a/packages/data-apis/src/generated/rest/portfolio.schema.ts +++ b/packages/data-apis/src/generated/rest/portfolio.schema.ts @@ -15,6 +15,33 @@ export type GetTokensByAddressBody = NonNullable< export type GetTokensByAddressResponse = operations["get-tokens-by-address"]["responses"]["200"]["content"]["application/json"]; +/** Request body for get-token-balances-by-address. */ +export type GetTokenBalancesByAddressBody = NonNullable< + operations["get-token-balances-by-address"]["requestBody"] +>["content"]["application/json"]; + +/** 200 response for get-token-balances-by-address. */ +export type GetTokenBalancesByAddressResponse = + operations["get-token-balances-by-address"]["responses"]["200"]["content"]["application/json"]; + +/** Request body for get-nfts-by-address. */ +export type GetNftsByAddressBody = NonNullable< + operations["get-nfts-by-address"]["requestBody"] +>["content"]["application/json"]; + +/** 200 response for get-nfts-by-address. */ +export type GetNftsByAddressResponse = + operations["get-nfts-by-address"]["responses"]["200"]["content"]["application/json"]; + +/** Request body for get-nft-contracts-by-address. */ +export type GetNftContractsByAddressBody = NonNullable< + operations["get-nft-contracts-by-address"]["requestBody"] +>["content"]["application/json"]; + +/** 200 response for get-nft-contracts-by-address. */ +export type GetNftContractsByAddressResponse = + operations["get-nft-contracts-by-address"]["responses"]["200"]["content"]["application/json"]; + /** RestRequestSchema entries for the portfolio REST API. */ export type PortfolioRestSchema = readonly [ { @@ -25,6 +52,30 @@ export type PortfolioRestSchema = readonly [ Query?: undefined; Response: GetTokensByAddressResponse; }, + { + /** POST /{apiKey}/assets/tokens/balances/by-address (operationId: get-token-balances-by-address) */ + Route: "assets/tokens/balances/by-address"; + Method: "POST"; + Body: GetTokenBalancesByAddressBody; + Query?: undefined; + Response: GetTokenBalancesByAddressResponse; + }, + { + /** POST /{apiKey}/assets/nfts/by-address (operationId: get-nfts-by-address) */ + Route: "assets/nfts/by-address"; + Method: "POST"; + Body: GetNftsByAddressBody; + Query?: undefined; + Response: GetNftsByAddressResponse; + }, + { + /** POST /{apiKey}/assets/nfts/contracts/by-address (operationId: get-nft-contracts-by-address) */ + Route: "assets/nfts/contracts/by-address"; + Method: "POST"; + Body: GetNftContractsByAddressBody; + Query?: undefined; + Response: GetNftContractsByAddressResponse; + }, ]; /** Compile-time guard that the emitted tuple satisfies the shared constraint. */ diff --git a/packages/data-apis/src/index.ts b/packages/data-apis/src/index.ts index 395254ca25..761cbffb7f 100644 --- a/packages/data-apis/src/index.ts +++ b/packages/data-apis/src/index.ts @@ -6,14 +6,50 @@ export { createDataClient } from "./client.js"; export type { DataActions } from "./decorator.js"; export { dataActions } from "./decorator.js"; +// per-request options +export type { RequestOptions } from "./internal/clientHelpers.js"; + // actions (individually importable for tree-shaking / composability) export { getTokensByAddress } from "./actions/portfolio/getTokensByAddress.js"; +export { getTokenBalancesByAddress } from "./actions/portfolio/getTokenBalancesByAddress.js"; +export { getNftsByAddress } from "./actions/portfolio/getNftsByAddress.js"; +export { getNftContractsByAddress } from "./actions/portfolio/getNftContractsByAddress.js"; +export { getTokenPricesBySymbol } from "./actions/prices/getTokenPricesBySymbol.js"; +export { getTokenPricesByAddress } from "./actions/prices/getTokenPricesByAddress.js"; +export { getHistoricalTokenPrices } from "./actions/prices/getHistoricalTokenPrices.js"; export { getNftsForOwner } from "./actions/nft/getNftsForOwner.js"; +export { getNftsForContract } from "./actions/nft/getNftsForContract.js"; +export { getNftsForCollection } from "./actions/nft/getNftsForCollection.js"; +export { getNftMetadata } from "./actions/nft/getNftMetadata.js"; +export { getNftMetadataBatch } from "./actions/nft/getNftMetadataBatch.js"; +export { getContractMetadata } from "./actions/nft/getContractMetadata.js"; +export { getContractMetadataBatch } from "./actions/nft/getContractMetadataBatch.js"; +export { getCollectionMetadata } from "./actions/nft/getCollectionMetadata.js"; +export { getContractsForOwner } from "./actions/nft/getContractsForOwner.js"; +export { getCollectionsForOwner } from "./actions/nft/getCollectionsForOwner.js"; +export { getOwnersForNft } from "./actions/nft/getOwnersForNft.js"; +export { getOwnersForContract } from "./actions/nft/getOwnersForContract.js"; +export { getNftSales } from "./actions/nft/getNftSales.js"; +export { getFloorPrice } from "./actions/nft/getFloorPrice.js"; +export { searchContractMetadata } from "./actions/nft/searchContractMetadata.js"; +export { getSpamContracts } from "./actions/nft/getSpamContracts.js"; +export { isSpamContract } from "./actions/nft/isSpamContract.js"; +export { isAirdropNft } from "./actions/nft/isAirdropNft.js"; +export { isHolderOfContract } from "./actions/nft/isHolderOfContract.js"; +export { computeRarity } from "./actions/nft/computeRarity.js"; +export { summarizeNftAttributes } from "./actions/nft/summarizeNftAttributes.js"; +export { getTokenBalances } from "./actions/token/getTokenBalances.js"; +export { getTokenMetadata } from "./actions/token/getTokenMetadata.js"; +export { getTokenAllowance } from "./actions/token/getTokenAllowance.js"; export { getAssetTransfers } from "./actions/transfers/getAssetTransfers.js"; // schemas export type { DataRpcSchema } from "./schema/rpc.js"; -export type { PortfolioRestSchema, NftRestSchema } from "./schema/rest.js"; +export type { + NftRestSchema, + PortfolioRestSchema, + PricesRestSchema, +} from "./schema/rest.js"; // types export type * from "./types.js"; diff --git a/packages/data-apis/src/internal/clientHelpers.ts b/packages/data-apis/src/internal/clientHelpers.ts index 7702afbc55..c90abde4fd 100644 --- a/packages/data-apis/src/internal/clientHelpers.ts +++ b/packages/data-apis/src/internal/clientHelpers.ts @@ -1,5 +1,6 @@ import { AlchemyRestClient, + alchemyTransport, resolveNetwork, type AlchemyTransport, type AlchemyTransportConfig, @@ -8,7 +9,9 @@ import { type RestRequestSchema, } from "@alchemy/common"; import { BaseError } from "@alchemy/common"; -import type { Chain, Client } from "viem"; +import type { Chain, Client, EIP1193RequestFn } from "viem"; +import { getRpcUrl } from "./endpoints.js"; +import type { DataRpcSchema } from "../schema/rpc.js"; /** The minimal client shape data actions operate on. */ export type DataClient = Client; @@ -78,3 +81,28 @@ export function getRestClient( const { apiKey, jwt } = getTransportConfig(client); return new AlchemyRestClient({ apiKey, jwt, url }); } + +/** + * Resolves the JSON-RPC request function for an action: the client's own + * transport when no override is given, otherwise a transport instance derived + * from the client's transport config and pointed at the override network's + * RPC URL (the same mechanism the transport's tracing support uses). + * + * @param {DataClient} client The client whose transport (and config) is used + * @param {NetworkInput} [network] Optional per-request network override + * @returns {EIP1193RequestFn} A typed JSON-RPC request function + */ +export function getRpcRequest( + client: DataClient, + network?: NetworkInput, +): EIP1193RequestFn { + if (!network) { + return client.request as EIP1193RequestFn; + } + const { slug } = resolveRequestNetwork(client, network); + const derived = alchemyTransport({ + ...getTransportConfig(client), + url: getRpcUrl(slug), + })({ retryCount: 0 }); + return derived.request as EIP1193RequestFn; +} diff --git a/packages/data-apis/src/internal/endpoints.ts b/packages/data-apis/src/internal/endpoints.ts index a870a9182f..8025b38e6b 100644 --- a/packages/data-apis/src/internal/endpoints.ts +++ b/packages/data-apis/src/internal/endpoints.ts @@ -4,6 +4,9 @@ /** Global, chain-agnostic Data API (multi-network request bodies). */ export const DATA_API_URL = "https://api.g.alchemy.com/data/v1"; +/** Global Prices API (chain-agnostic or networks in the request body). */ +export const PRICES_API_URL = "https://api.g.alchemy.com/prices/v1"; + /** * Network-scoped NFT v3 base URL. * diff --git a/packages/data-apis/src/internal/query.ts b/packages/data-apis/src/internal/query.ts new file mode 100644 index 0000000000..1db0f2bdd5 --- /dev/null +++ b/packages/data-apis/src/internal/query.ts @@ -0,0 +1,19 @@ +/** + * Restores wire-format bracketed keys ("contractAddresses[]") that the public + * params surface exposes unbracketed (the inverse of the `Unbracket` mapped + * type in types.ts). Keys not listed pass through untouched. + * + * @param {Record} params The unbracketed params object + * @param {string[]} arrayKeys Keys to re-bracket + * @returns {Record} The wire-format query object + */ +export function bracketArrayKeys( + params: Record, + arrayKeys: readonly string[], +): Record { + const out: Record = {}; + for (const [key, value] of Object.entries(params)) { + out[arrayKeys.includes(key) ? `${key}[]` : key] = value; + } + return out; +} diff --git a/packages/data-apis/src/schema/rest.ts b/packages/data-apis/src/schema/rest.ts index a725eb72c5..ee5c5bc696 100644 --- a/packages/data-apis/src/schema/rest.ts +++ b/packages/data-apis/src/schema/rest.ts @@ -3,3 +3,4 @@ // stable regardless of how generation is organized internally. export type { NftRestSchema } from "../generated/rest/nft.schema.js"; export type { PortfolioRestSchema } from "../generated/rest/portfolio.schema.js"; +export type { PricesRestSchema } from "../generated/rest/prices.schema.js"; diff --git a/packages/data-apis/src/schema/rpc.ts b/packages/data-apis/src/schema/rpc.ts index fb3b5fec9d..510f728ce2 100644 --- a/packages/data-apis/src/schema/rpc.ts +++ b/packages/data-apis/src/schema/rpc.ts @@ -1,4 +1,8 @@ -import type { AlchemyGetAssetTransfersParams } from "../generated/rpc/transfers.js"; +import type { TokenRpcSchema } from "../generated/rpc/token.js"; +import type { + AlchemyGetAssetTransfersParams, + TransfersRpcSchema, +} from "../generated/rpc/transfers.js"; import type { GetAssetTransfersResult } from "../types.js"; // Params/result internals are generated by @alchemy/api-codegen from the docs @@ -10,13 +14,15 @@ export type GetAssetTransfersRpcParams = AlchemyGetAssetTransfersParams; * viem RpcSchema entries for the Data JSON-RPC methods. Attach to a client to * get typed `client.request({ method: "alchemy_getAssetTransfers", ... })`. * - * ReturnType uses the SDK's {@link GetAssetTransfersResult}, which collapses - * the spec's "Not Found (null)" string branch (a docs-spec artifact). + * The transfers ReturnType uses the SDK's {@link GetAssetTransfersResult}, + * which collapses the spec's "Not Found (null)" string branch (a docs-spec + * artifact). */ export type DataRpcSchema = [ { - Method: "alchemy_getAssetTransfers"; - Parameters: [AlchemyGetAssetTransfersParams]; + Method: TransfersRpcSchema[0]["Method"]; + Parameters: TransfersRpcSchema[0]["Parameters"]; ReturnType: GetAssetTransfersResult; }, + ...TokenRpcSchema, ]; diff --git a/packages/data-apis/src/types.ts b/packages/data-apis/src/types.ts index 6c848d7b1d..c50caef5e8 100644 --- a/packages/data-apis/src/types.ts +++ b/packages/data-apis/src/types.ts @@ -1,12 +1,75 @@ import type { NetworkInput } from "@alchemy/common"; import type { + ComputeRarityQuery, + ComputeRarityResponse, + GetCollectionMetadataQuery, + GetCollectionMetadataResponse, + GetCollectionsForOwnerQuery, + GetCollectionsForOwnerResponse, + GetContractMetadataBatchBody, + GetContractMetadataBatchResponse, + GetContractMetadataQuery, + GetContractMetadataResponse, + GetContractsForOwnerQuery, + GetContractsForOwnerResponse, + GetFloorPriceQuery, + GetFloorPriceResponse, + GetNftMetadataBatchBody, + GetNftMetadataBatchResponse, + GetNftMetadataQuery, + GetNftMetadataResponse, + GetNftSalesQuery, + GetNftSalesResponse, + GetNftsForCollectionQuery, + GetNftsForCollectionResponse, + GetNftsForContractQuery, + GetNftsForContractResponse, GetNftsForOwnerQuery, GetNftsForOwnerResponse, + GetOwnersForContractQuery, + GetOwnersForContractResponse, + GetOwnersForNftQuery, + GetOwnersForNftResponse, + GetSpamContractsResponse, + IsAirdropNftQuery, + IsAirdropNftResponse, + IsHolderOfContractQuery, + IsHolderOfContractResponse, + IsSpamContractQuery, + IsSpamContractResponse, + SearchContractMetadataQuery, + SearchContractMetadataResponse, + SummarizeNftAttributesQuery, + SummarizeNftAttributesResponse, } from "./generated/rest/nft.schema.js"; import type { + GetNftContractsByAddressBody, + GetNftContractsByAddressResponse, + GetNftsByAddressBody, + GetNftsByAddressResponse, + GetTokenBalancesByAddressBody, + GetTokenBalancesByAddressResponse, GetTokensByAddressBody, GetTokensByAddressResponse, } from "./generated/rest/portfolio.schema.js"; +import type { + GetHistoricalTokenPricesBody, + GetHistoricalTokenPricesResponse, + GetTokenPricesByAddressBody, + GetTokenPricesByAddressResponse, + GetTokenPricesBySymbolQuery, + GetTokenPricesBySymbolResponse, +} from "./generated/rest/prices.schema.js"; +import type { + AlchemyGetTokenAllowanceParams, + AlchemyGetTokenAllowanceResult, + AlchemyGetTokenBalancesAddressParam, + AlchemyGetTokenBalancesOptionsParam, + AlchemyGetTokenBalancesResult, + AlchemyGetTokenBalancesTokenSpecParam, + AlchemyGetTokenMetadataParams, + AlchemyGetTokenMetadataResult, +} from "./generated/rpc/token.js"; import type { AlchemyGetAssetTransfersParams, AlchemyGetAssetTransfersResult, @@ -18,6 +81,24 @@ import type { // re-exported directly: every public-surface change is a deliberate edit // here, even when the underlying spec moves. +/** Renames wire keys like "contractAddresses[]" to plain names; actions map them back. */ +type Unbracket = { + [K in keyof T as K extends `${infer Base}[]` ? Base : K]: T[K]; +}; + +/** Query params of a network-scoped method, plus the SDK's network override. */ +type NetworkScoped = Unbracket & { + /** Overrides the client-level network for this request. */ + network?: NetworkInput; +}; + +/** Distributes over a union, replacing wire `network: string` with NetworkInput. */ +type WithNetworkInput = T extends { network: string } + ? Omit & { network: NetworkInput } + : T; + +// ─── Portfolio (REST, global, multi-network) ──────────────────────────────── + /** An address paired with the networks to query it on. */ export interface PortfolioAddressEntry { address: string; @@ -26,38 +107,176 @@ export interface PortfolioAddressEntry { } /** - * Generated request body with the wire-format `addresses` (plain string - * networks) replaced by the SDK's three-format {@link PortfolioAddressEntry}. + * Replaces each wire-format address entry's `networks` (slug strings — an + * enum in some specs, deliberately widened here to support the SDK's + * escape-hatch slugs) with the SDK's three-format NetworkInput, preserving + * any other per-entry fields the operation defines (e.g. per-address + * include/exclude filters). */ -export type GetTokensByAddressParams = Omit< - GetTokensByAddressBody, +type PortfolioParams = Omit< + Body, "addresses" > & { - addresses: PortfolioAddressEntry[]; + addresses: Array< + Omit & { + /** Networks to query; accepts viem Chains, Alchemy slugs, or CAIP-2 ids. */ + networks: NetworkInput[]; + } + >; }; +export type GetTokensByAddressParams = PortfolioParams; export type GetTokensByAddressResult = GetTokensByAddressResponse; - export type PortfolioToken = NonNullable< GetTokensByAddressResponse["data"]["tokens"] >[number]; -/** - * Generated query params plus the SDK's network override; the wire's - * bracketed `contractAddresses[]` key is replaced with a plain array (the - * action serializes it back to the bracketed form). - */ -export type GetNftsForOwnerParams = Omit< - GetNftsForOwnerQuery, - "contractAddresses[]" +export type GetTokenBalancesByAddressParams = + PortfolioParams; +export type GetTokenBalancesByAddressResult = GetTokenBalancesByAddressResponse; + +export type GetNftsByAddressParams = PortfolioParams; +export type GetNftsByAddressResult = GetNftsByAddressResponse; + +export type GetNftContractsByAddressParams = + PortfolioParams; +export type GetNftContractsByAddressResult = GetNftContractsByAddressResponse; + +// ─── Prices (REST, global) ─────────────────────────────────────────────────── + +/** Chain-agnostic: token symbols only, no network involved. */ +export type GetTokenPricesBySymbolParams = GetTokenPricesBySymbolQuery; +export type GetTokenPricesBySymbolResult = GetTokenPricesBySymbolResponse; + +/** A token address paired with the network it lives on. */ +export interface PriceAddressEntry { + address: string; + /** Accepts a viem Chain, an Alchemy slug, or a CAIP-2 id. */ + network: NetworkInput; +} + +export type GetTokenPricesByAddressParams = Omit< + GetTokenPricesByAddressBody, + "addresses" > & { + addresses: PriceAddressEntry[]; +}; +export type GetTokenPricesByAddressResult = GetTokenPricesByAddressResponse; + +export type GetHistoricalTokenPricesParams = + WithNetworkInput; +export type GetHistoricalTokenPricesResult = GetHistoricalTokenPricesResponse; + +// ─── NFT (REST, network-scoped) ────────────────────────────────────────────── + +export type GetNftsForOwnerParams = NetworkScoped; +export type GetNftsForOwnerResult = GetNftsForOwnerResponse; + +export type GetNftsForContractParams = NetworkScoped; +export type GetNftsForContractResult = GetNftsForContractResponse; + +export type GetNftsForCollectionParams = + NetworkScoped; +export type GetNftsForCollectionResult = GetNftsForCollectionResponse; + +export type GetNftMetadataParams = NetworkScoped; +export type GetNftMetadataResult = GetNftMetadataResponse; + +export type GetNftMetadataBatchParams = GetNftMetadataBatchBody & { /** Overrides the client-level network for this request. */ network?: NetworkInput; - /** Contract addresses to filter by (max 45). */ - contractAddresses?: string[]; }; +export type GetNftMetadataBatchResult = GetNftMetadataBatchResponse; -export type GetNftsForOwnerResult = GetNftsForOwnerResponse; +export type GetContractMetadataParams = NetworkScoped; +export type GetContractMetadataResult = GetContractMetadataResponse; + +export type GetContractMetadataBatchParams = GetContractMetadataBatchBody & { + /** Overrides the client-level network for this request. */ + network?: NetworkInput; +}; +export type GetContractMetadataBatchResult = GetContractMetadataBatchResponse; + +export type GetCollectionMetadataParams = + NetworkScoped; +export type GetCollectionMetadataResult = GetCollectionMetadataResponse; + +export type GetContractsForOwnerParams = + NetworkScoped; +export type GetContractsForOwnerResult = GetContractsForOwnerResponse; + +export type GetCollectionsForOwnerParams = + NetworkScoped; +export type GetCollectionsForOwnerResult = GetCollectionsForOwnerResponse; + +export type GetOwnersForNftParams = NetworkScoped; +export type GetOwnersForNftResult = GetOwnersForNftResponse; + +export type GetOwnersForContractParams = + NetworkScoped; +export type GetOwnersForContractResult = GetOwnersForContractResponse; + +export type GetNftSalesParams = NetworkScoped; +export type GetNftSalesResult = GetNftSalesResponse; + +export type GetFloorPriceParams = NetworkScoped; +export type GetFloorPriceResult = GetFloorPriceResponse; + +export type SearchContractMetadataParams = + NetworkScoped; +export type SearchContractMetadataResult = SearchContractMetadataResponse; + +export type GetSpamContractsParams = { + /** Overrides the client-level network for this request. */ + network?: NetworkInput; +}; +export type GetSpamContractsResult = GetSpamContractsResponse; + +export type IsSpamContractParams = NetworkScoped; +export type IsSpamContractResult = IsSpamContractResponse; + +export type IsAirdropNftParams = NetworkScoped; +export type IsAirdropNftResult = IsAirdropNftResponse; + +export type IsHolderOfContractParams = NetworkScoped; +export type IsHolderOfContractResult = IsHolderOfContractResponse; + +export type ComputeRarityParams = NetworkScoped; +export type ComputeRarityResult = ComputeRarityResponse; + +export type SummarizeNftAttributesParams = + NetworkScoped; +export type SummarizeNftAttributesResult = SummarizeNftAttributesResponse; + +// ─── Token (JSON-RPC, network-scoped) ──────────────────────────────────────── + +export type GetTokenBalancesParams = { + /** The address to fetch balances for. */ + address: AlchemyGetTokenBalancesAddressParam; + /** "erc20" | "NATIVE_TOKEN" | "DEFAULT_TOKENS" or an explicit contract list. */ + tokenSpec?: AlchemyGetTokenBalancesTokenSpecParam; + /** Paging options (pageKey/maxCount; only valid with the "erc20" spec). */ + options?: AlchemyGetTokenBalancesOptionsParam; + /** Overrides the client-level network for this request. */ + network?: NetworkInput; +}; +export type GetTokenBalancesResult = AlchemyGetTokenBalancesResult; + +export type GetTokenMetadataParams = { + /** The token contract address. */ + contractAddress: AlchemyGetTokenMetadataParams; + /** Overrides the client-level network for this request. */ + network?: NetworkInput; +}; +export type GetTokenMetadataResult = AlchemyGetTokenMetadataResult; + +export type GetTokenAllowanceParams = AlchemyGetTokenAllowanceParams & { + /** Overrides the client-level network for this request. */ + network?: NetworkInput; +}; +export type GetTokenAllowanceResult = AlchemyGetTokenAllowanceResult; + +// ─── Transfers (JSON-RPC, network-scoped) ──────────────────────────────────── /** Generated RPC params plus the SDK's network override. */ export type GetAssetTransfersParams = AlchemyGetAssetTransfersParams & { From 45d136e2f65eb486681c352a952cbe3eea779bd8 Mon Sep 17 00:00:00 2001 From: blake duncan Date: Wed, 10 Jun 2026 11:04:30 -0400 Subject: [PATCH 5/8] feat(data-apis): pagination iterators and normalized errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - paginate(): shared async-generator driver yielding whole pages; stops on missing/empty cursors, throws on a repeated cursor (infinite-loop guard), supports AbortSignal + maxPages - 9 *Pages companion actions for every paginated method (nft owner/contract/ collection listings + sales, portfolio nfts/contracts by address, transfers), wired into the decorator namespaces; cursor wiring (pageKey vs startToken→pageKey/nextToken, body vs query vs rpc-param) follows the manifest's validated pagination metadata - wrapRpcError(): JSON-RPC failures normalize into AlchemyApiError (code/ status), with /v2/ and apiKey query credentials redacted from any URL-bearing text — keys never leak through error chains. REST is already normalized inside AlchemyRestClient. - 10 new tests (cursor walking, repeat-cursor guard, maxPages, consumer break, abort, redaction, error mapping) + a decorator-level paging test Co-Authored-By: Claude Fable 5 --- .../nft/getCollectionsForOwnerPages.ts | 34 ++++++ .../actions/nft/getContractsForOwnerPages.ts | 30 +++++ .../src/actions/nft/getNftSalesPages.ts | 27 +++++ .../actions/nft/getNftsForCollectionPages.ts | 34 ++++++ .../actions/nft/getNftsForContractPages.ts | 30 +++++ .../src/actions/nft/getNftsForOwnerPages.ts | 30 +++++ .../data-apis/src/actions/nft/nft.test.ts | 20 ++++ .../getNftContractsByAddressPages.ts | 34 ++++++ .../portfolio/getNftsByAddressPages.ts | 30 +++++ .../src/actions/token/getTokenAllowance.ts | 3 +- .../src/actions/token/getTokenBalances.ts | 3 +- .../src/actions/token/getTokenMetadata.ts | 3 +- .../actions/transfers/getAssetTransfers.ts | 3 +- .../transfers/getAssetTransfersPages.ts | 31 ++++++ packages/data-apis/src/decorator.ts | 66 +++++++++++ packages/data-apis/src/index.ts | 10 ++ .../data-apis/src/internal/errors.test.ts | 67 +++++++++++ packages/data-apis/src/internal/errors.ts | 46 ++++++++ .../data-apis/src/internal/paginate.test.ts | 104 ++++++++++++++++++ packages/data-apis/src/internal/paginate.ts | 55 +++++++++ 20 files changed, 656 insertions(+), 4 deletions(-) create mode 100644 packages/data-apis/src/actions/nft/getCollectionsForOwnerPages.ts create mode 100644 packages/data-apis/src/actions/nft/getContractsForOwnerPages.ts create mode 100644 packages/data-apis/src/actions/nft/getNftSalesPages.ts create mode 100644 packages/data-apis/src/actions/nft/getNftsForCollectionPages.ts create mode 100644 packages/data-apis/src/actions/nft/getNftsForContractPages.ts create mode 100644 packages/data-apis/src/actions/nft/getNftsForOwnerPages.ts create mode 100644 packages/data-apis/src/actions/portfolio/getNftContractsByAddressPages.ts create mode 100644 packages/data-apis/src/actions/portfolio/getNftsByAddressPages.ts create mode 100644 packages/data-apis/src/actions/transfers/getAssetTransfersPages.ts create mode 100644 packages/data-apis/src/internal/errors.test.ts create mode 100644 packages/data-apis/src/internal/errors.ts create mode 100644 packages/data-apis/src/internal/paginate.test.ts create mode 100644 packages/data-apis/src/internal/paginate.ts diff --git a/packages/data-apis/src/actions/nft/getCollectionsForOwnerPages.ts b/packages/data-apis/src/actions/nft/getCollectionsForOwnerPages.ts new file mode 100644 index 0000000000..5083f9a80f --- /dev/null +++ b/packages/data-apis/src/actions/nft/getCollectionsForOwnerPages.ts @@ -0,0 +1,34 @@ +import { paginate, type PaginateOptions } from "../../internal/paginate.js"; +import type { DataClient } from "../../internal/clientHelpers.js"; +import { getCollectionsForOwner } from "./getCollectionsForOwner.js"; +import type { + GetCollectionsForOwnerParams, + GetCollectionsForOwnerResult, +} from "../../types.js"; + +/** + * Auto-paginating companion to {@link getCollectionsForOwner}: yields whole pages until the + * cursor is exhausted (or `maxPages` is hit), guarding against repeated + * cursors. Iterate items with an inner loop over each page. + * + * @param {DataClient} client A client configured with an Alchemy transport + * @param {GetCollectionsForOwnerParams} params Same params as getCollectionsForOwner (the cursor is managed for you) + * @param {PaginateOptions} [options] Abort signal and page cap + * @returns {AsyncGenerator} Pages, in order + */ +export function getCollectionsForOwnerPages( + client: DataClient, + params: GetCollectionsForOwnerParams, + options?: PaginateOptions, +): AsyncGenerator { + return paginate({ + fetchPage: (cursor, signal) => + getCollectionsForOwner( + client, + { ...params, pageKey: cursor }, + { signal }, + ), + nextCursor: (page) => page.pageKey, + options, + }); +} diff --git a/packages/data-apis/src/actions/nft/getContractsForOwnerPages.ts b/packages/data-apis/src/actions/nft/getContractsForOwnerPages.ts new file mode 100644 index 0000000000..12ac4d3737 --- /dev/null +++ b/packages/data-apis/src/actions/nft/getContractsForOwnerPages.ts @@ -0,0 +1,30 @@ +import { paginate, type PaginateOptions } from "../../internal/paginate.js"; +import type { DataClient } from "../../internal/clientHelpers.js"; +import { getContractsForOwner } from "./getContractsForOwner.js"; +import type { + GetContractsForOwnerParams, + GetContractsForOwnerResult, +} from "../../types.js"; + +/** + * Auto-paginating companion to {@link getContractsForOwner}: yields whole pages until the + * cursor is exhausted (or `maxPages` is hit), guarding against repeated + * cursors. Iterate items with an inner loop over each page. + * + * @param {DataClient} client A client configured with an Alchemy transport + * @param {GetContractsForOwnerParams} params Same params as getContractsForOwner (the cursor is managed for you) + * @param {PaginateOptions} [options] Abort signal and page cap + * @returns {AsyncGenerator} Pages, in order + */ +export function getContractsForOwnerPages( + client: DataClient, + params: GetContractsForOwnerParams, + options?: PaginateOptions, +): AsyncGenerator { + return paginate({ + fetchPage: (cursor, signal) => + getContractsForOwner(client, { ...params, pageKey: cursor }, { signal }), + nextCursor: (page) => page.pageKey, + options, + }); +} diff --git a/packages/data-apis/src/actions/nft/getNftSalesPages.ts b/packages/data-apis/src/actions/nft/getNftSalesPages.ts new file mode 100644 index 0000000000..9666fecbf4 --- /dev/null +++ b/packages/data-apis/src/actions/nft/getNftSalesPages.ts @@ -0,0 +1,27 @@ +import { paginate, type PaginateOptions } from "../../internal/paginate.js"; +import type { DataClient } from "../../internal/clientHelpers.js"; +import { getNftSales } from "./getNftSales.js"; +import type { GetNftSalesParams, GetNftSalesResult } from "../../types.js"; + +/** + * Auto-paginating companion to {@link getNftSales}: yields whole pages until the + * cursor is exhausted (or `maxPages` is hit), guarding against repeated + * cursors. Iterate items with an inner loop over each page. + * + * @param {DataClient} client A client configured with an Alchemy transport + * @param {GetNftSalesParams} params Same params as getNftSales (the cursor is managed for you) + * @param {PaginateOptions} [options] Abort signal and page cap + * @returns {AsyncGenerator} Pages, in order + */ +export function getNftSalesPages( + client: DataClient, + params: GetNftSalesParams, + options?: PaginateOptions, +): AsyncGenerator { + return paginate({ + fetchPage: (cursor, signal) => + getNftSales(client, { ...params, pageKey: cursor }, { signal }), + nextCursor: (page) => page.pageKey, + options, + }); +} diff --git a/packages/data-apis/src/actions/nft/getNftsForCollectionPages.ts b/packages/data-apis/src/actions/nft/getNftsForCollectionPages.ts new file mode 100644 index 0000000000..36690396fb --- /dev/null +++ b/packages/data-apis/src/actions/nft/getNftsForCollectionPages.ts @@ -0,0 +1,34 @@ +import { paginate, type PaginateOptions } from "../../internal/paginate.js"; +import type { DataClient } from "../../internal/clientHelpers.js"; +import { getNftsForCollection } from "./getNftsForCollection.js"; +import type { + GetNftsForCollectionParams, + GetNftsForCollectionResult, +} from "../../types.js"; + +/** + * Auto-paginating companion to {@link getNftsForCollection}: yields whole pages until the + * cursor is exhausted (or `maxPages` is hit), guarding against repeated + * cursors. Iterate items with an inner loop over each page. + * + * @param {DataClient} client A client configured with an Alchemy transport + * @param {GetNftsForCollectionParams} params Same params as getNftsForCollection (the cursor is managed for you) + * @param {PaginateOptions} [options] Abort signal and page cap + * @returns {AsyncGenerator} Pages, in order + */ +export function getNftsForCollectionPages( + client: DataClient, + params: GetNftsForCollectionParams, + options?: PaginateOptions, +): AsyncGenerator { + return paginate({ + fetchPage: (cursor, signal) => + getNftsForCollection( + client, + { ...params, startToken: cursor }, + { signal }, + ), + nextCursor: (page) => page.nextToken, + options, + }); +} diff --git a/packages/data-apis/src/actions/nft/getNftsForContractPages.ts b/packages/data-apis/src/actions/nft/getNftsForContractPages.ts new file mode 100644 index 0000000000..9a01140267 --- /dev/null +++ b/packages/data-apis/src/actions/nft/getNftsForContractPages.ts @@ -0,0 +1,30 @@ +import { paginate, type PaginateOptions } from "../../internal/paginate.js"; +import type { DataClient } from "../../internal/clientHelpers.js"; +import { getNftsForContract } from "./getNftsForContract.js"; +import type { + GetNftsForContractParams, + GetNftsForContractResult, +} from "../../types.js"; + +/** + * Auto-paginating companion to {@link getNftsForContract}: yields whole pages until the + * cursor is exhausted (or `maxPages` is hit), guarding against repeated + * cursors. Iterate items with an inner loop over each page. + * + * @param {DataClient} client A client configured with an Alchemy transport + * @param {GetNftsForContractParams} params Same params as getNftsForContract (the cursor is managed for you) + * @param {PaginateOptions} [options] Abort signal and page cap + * @returns {AsyncGenerator} Pages, in order + */ +export function getNftsForContractPages( + client: DataClient, + params: GetNftsForContractParams, + options?: PaginateOptions, +): AsyncGenerator { + return paginate({ + fetchPage: (cursor, signal) => + getNftsForContract(client, { ...params, startToken: cursor }, { signal }), + nextCursor: (page) => page.pageKey, + options, + }); +} diff --git a/packages/data-apis/src/actions/nft/getNftsForOwnerPages.ts b/packages/data-apis/src/actions/nft/getNftsForOwnerPages.ts new file mode 100644 index 0000000000..d8621d7fbd --- /dev/null +++ b/packages/data-apis/src/actions/nft/getNftsForOwnerPages.ts @@ -0,0 +1,30 @@ +import { paginate, type PaginateOptions } from "../../internal/paginate.js"; +import type { DataClient } from "../../internal/clientHelpers.js"; +import { getNftsForOwner } from "./getNftsForOwner.js"; +import type { + GetNftsForOwnerParams, + GetNftsForOwnerResult, +} from "../../types.js"; + +/** + * Auto-paginating companion to {@link getNftsForOwner}: yields whole pages until the + * cursor is exhausted (or `maxPages` is hit), guarding against repeated + * cursors. Iterate items with an inner loop over each page. + * + * @param {DataClient} client A client configured with an Alchemy transport + * @param {GetNftsForOwnerParams} params Same params as getNftsForOwner (the cursor is managed for you) + * @param {PaginateOptions} [options] Abort signal and page cap + * @returns {AsyncGenerator} Pages, in order + */ +export function getNftsForOwnerPages( + client: DataClient, + params: GetNftsForOwnerParams, + options?: PaginateOptions, +): AsyncGenerator { + return paginate({ + fetchPage: (cursor, signal) => + getNftsForOwner(client, { ...params, pageKey: cursor }, { signal }), + nextCursor: (page) => page.pageKey, + options, + }); +} diff --git a/packages/data-apis/src/actions/nft/nft.test.ts b/packages/data-apis/src/actions/nft/nft.test.ts index 6a2ed6bfce..4d0d2f8842 100644 --- a/packages/data-apis/src/actions/nft/nft.test.ts +++ b/packages/data-apis/src/actions/nft/nft.test.ts @@ -172,4 +172,24 @@ describe("nft namespace routing", () => { "https://base-mainnet.g.alchemy.com/nft/v3/getContractMetadata?contractAddress=0xc", ); }); + + it("getNftsForOwnerPages threads cursors through query params", async () => { + fetchMock + .mockImplementationOnce(async () => + jsonResponse({ ownedNfts: [{}], pageKey: "page-2" }), + ) + .mockImplementationOnce(async () => jsonResponse({ ownedNfts: [{}] })); + + const pages = []; + for await (const page of makeClient().nft.getNftsForOwnerPages({ + owner: "0xo", + })) { + pages.push(page); + } + expect(pages).toHaveLength(2); + const url1 = new URL(String(fetchMock.mock.calls[0]![0])); + const url2 = new URL(String(fetchMock.mock.calls[1]![0])); + expect(url1.searchParams.get("pageKey")).toBeNull(); + expect(url2.searchParams.get("pageKey")).toBe("page-2"); + }); }); diff --git a/packages/data-apis/src/actions/portfolio/getNftContractsByAddressPages.ts b/packages/data-apis/src/actions/portfolio/getNftContractsByAddressPages.ts new file mode 100644 index 0000000000..9e482ba75d --- /dev/null +++ b/packages/data-apis/src/actions/portfolio/getNftContractsByAddressPages.ts @@ -0,0 +1,34 @@ +import { paginate, type PaginateOptions } from "../../internal/paginate.js"; +import type { DataClient } from "../../internal/clientHelpers.js"; +import { getNftContractsByAddress } from "./getNftContractsByAddress.js"; +import type { + GetNftContractsByAddressParams, + GetNftContractsByAddressResult, +} from "../../types.js"; + +/** + * Auto-paginating companion to {@link getNftContractsByAddress}: yields whole pages until the + * cursor is exhausted (or `maxPages` is hit), guarding against repeated + * cursors. Iterate items with an inner loop over each page. + * + * @param {DataClient} client A client configured with an Alchemy transport + * @param {GetNftContractsByAddressParams} params Same params as getNftContractsByAddress (the cursor is managed for you) + * @param {PaginateOptions} [options] Abort signal and page cap + * @returns {AsyncGenerator} Pages, in order + */ +export function getNftContractsByAddressPages( + client: DataClient, + params: GetNftContractsByAddressParams, + options?: PaginateOptions, +): AsyncGenerator { + return paginate({ + fetchPage: (cursor, signal) => + getNftContractsByAddress( + client, + { ...params, pageKey: cursor }, + { signal }, + ), + nextCursor: (page) => page.data.pageKey, + options, + }); +} diff --git a/packages/data-apis/src/actions/portfolio/getNftsByAddressPages.ts b/packages/data-apis/src/actions/portfolio/getNftsByAddressPages.ts new file mode 100644 index 0000000000..afba5134d4 --- /dev/null +++ b/packages/data-apis/src/actions/portfolio/getNftsByAddressPages.ts @@ -0,0 +1,30 @@ +import { paginate, type PaginateOptions } from "../../internal/paginate.js"; +import type { DataClient } from "../../internal/clientHelpers.js"; +import { getNftsByAddress } from "./getNftsByAddress.js"; +import type { + GetNftsByAddressParams, + GetNftsByAddressResult, +} from "../../types.js"; + +/** + * Auto-paginating companion to {@link getNftsByAddress}: yields whole pages until the + * cursor is exhausted (or `maxPages` is hit), guarding against repeated + * cursors. Iterate items with an inner loop over each page. + * + * @param {DataClient} client A client configured with an Alchemy transport + * @param {GetNftsByAddressParams} params Same params as getNftsByAddress (the cursor is managed for you) + * @param {PaginateOptions} [options] Abort signal and page cap + * @returns {AsyncGenerator} Pages, in order + */ +export function getNftsByAddressPages( + client: DataClient, + params: GetNftsByAddressParams, + options?: PaginateOptions, +): AsyncGenerator { + return paginate({ + fetchPage: (cursor, signal) => + getNftsByAddress(client, { ...params, pageKey: cursor }, { signal }), + nextCursor: (page) => page.data.pageKey, + options, + }); +} diff --git a/packages/data-apis/src/actions/token/getTokenAllowance.ts b/packages/data-apis/src/actions/token/getTokenAllowance.ts index 67cb94315d..d4b311e30b 100644 --- a/packages/data-apis/src/actions/token/getTokenAllowance.ts +++ b/packages/data-apis/src/actions/token/getTokenAllowance.ts @@ -2,6 +2,7 @@ import { getRpcRequest, type DataClient, } from "../../internal/clientHelpers.js"; +import { wrapRpcError } from "../../internal/errors.js"; import type { GetTokenAllowanceParams, GetTokenAllowanceResult, @@ -26,5 +27,5 @@ export async function getTokenAllowance( return request({ method: "alchemy_getTokenAllowance", params: [allowanceRequest], - }); + }).catch(wrapRpcError); } diff --git a/packages/data-apis/src/actions/token/getTokenBalances.ts b/packages/data-apis/src/actions/token/getTokenBalances.ts index c303ef7742..1c49066af3 100644 --- a/packages/data-apis/src/actions/token/getTokenBalances.ts +++ b/packages/data-apis/src/actions/token/getTokenBalances.ts @@ -2,6 +2,7 @@ import { getRpcRequest, type DataClient, } from "../../internal/clientHelpers.js"; +import { wrapRpcError } from "../../internal/errors.js"; import type { TokenRpcSchema } from "../../generated/rpc/token.js"; import type { GetTokenBalancesParams, @@ -38,5 +39,5 @@ export async function getTokenBalances( return request({ method: "alchemy_getTokenBalances", params: rpcParams, - }); + }).catch(wrapRpcError); } diff --git a/packages/data-apis/src/actions/token/getTokenMetadata.ts b/packages/data-apis/src/actions/token/getTokenMetadata.ts index 7b9593fad4..5b04484e07 100644 --- a/packages/data-apis/src/actions/token/getTokenMetadata.ts +++ b/packages/data-apis/src/actions/token/getTokenMetadata.ts @@ -2,6 +2,7 @@ import { getRpcRequest, type DataClient, } from "../../internal/clientHelpers.js"; +import { wrapRpcError } from "../../internal/errors.js"; import type { GetTokenMetadataParams, GetTokenMetadataResult, @@ -26,5 +27,5 @@ export async function getTokenMetadata( return request({ method: "alchemy_getTokenMetadata", params: [contractAddress], - }); + }).catch(wrapRpcError); } diff --git a/packages/data-apis/src/actions/transfers/getAssetTransfers.ts b/packages/data-apis/src/actions/transfers/getAssetTransfers.ts index 796edad0ab..3a4aa02e38 100644 --- a/packages/data-apis/src/actions/transfers/getAssetTransfers.ts +++ b/packages/data-apis/src/actions/transfers/getAssetTransfers.ts @@ -2,6 +2,7 @@ import { getRpcRequest, type DataClient, } from "../../internal/clientHelpers.js"; +import { wrapRpcError } from "../../internal/errors.js"; import type { GetAssetTransfersParams, GetAssetTransfersResult, @@ -29,5 +30,5 @@ export async function getAssetTransfers( return request({ method: "alchemy_getAssetTransfers", params: [rpcParams], - }); + }).catch(wrapRpcError); } diff --git a/packages/data-apis/src/actions/transfers/getAssetTransfersPages.ts b/packages/data-apis/src/actions/transfers/getAssetTransfersPages.ts new file mode 100644 index 0000000000..e2ba8df0d7 --- /dev/null +++ b/packages/data-apis/src/actions/transfers/getAssetTransfersPages.ts @@ -0,0 +1,31 @@ +import { paginate, type PaginateOptions } from "../../internal/paginate.js"; +import type { DataClient } from "../../internal/clientHelpers.js"; +import { getAssetTransfers } from "./getAssetTransfers.js"; +import type { + GetAssetTransfersParams, + GetAssetTransfersResult, +} from "../../types.js"; + +/** + * Auto-paginating companion to {@link getAssetTransfers}: yields whole pages + * until the cursor is exhausted (or `maxPages` is hit), guarding against + * repeated cursors. Note: JSON-RPC requests run through the client's viem + * transport, which owns the fetch — the abort signal is honored between + * pages, not mid-request. + * + * @param {DataClient} client A client configured with an Alchemy transport + * @param {GetAssetTransfersParams} params Same params as getAssetTransfers (the cursor is managed for you) + * @param {PaginateOptions} [options] Abort signal (checked between pages) and page cap + * @returns {AsyncGenerator} Pages, in order + */ +export function getAssetTransfersPages( + client: DataClient, + params: GetAssetTransfersParams, + options?: PaginateOptions, +): AsyncGenerator { + return paginate({ + fetchPage: (pageKey) => getAssetTransfers(client, { ...params, pageKey }), + nextCursor: (page) => page.pageKey, + options, + }); +} diff --git a/packages/data-apis/src/decorator.ts b/packages/data-apis/src/decorator.ts index 2d736cc9f5..a1799532dc 100644 --- a/packages/data-apis/src/decorator.ts +++ b/packages/data-apis/src/decorator.ts @@ -1,10 +1,13 @@ import type { DataClient, RequestOptions } from "./internal/clientHelpers.js"; +import type { PaginateOptions } from "./internal/paginate.js"; import type * as T from "./types.js"; import { getTokensByAddress } from "./actions/portfolio/getTokensByAddress.js"; import { getTokenBalancesByAddress } from "./actions/portfolio/getTokenBalancesByAddress.js"; import { getNftsByAddress } from "./actions/portfolio/getNftsByAddress.js"; import { getNftContractsByAddress } from "./actions/portfolio/getNftContractsByAddress.js"; +import { getNftsByAddressPages } from "./actions/portfolio/getNftsByAddressPages.js"; +import { getNftContractsByAddressPages } from "./actions/portfolio/getNftContractsByAddressPages.js"; import { getTokenPricesBySymbol } from "./actions/prices/getTokenPricesBySymbol.js"; import { getTokenPricesByAddress } from "./actions/prices/getTokenPricesByAddress.js"; @@ -31,12 +34,19 @@ import { isAirdropNft } from "./actions/nft/isAirdropNft.js"; import { isHolderOfContract } from "./actions/nft/isHolderOfContract.js"; import { computeRarity } from "./actions/nft/computeRarity.js"; import { summarizeNftAttributes } from "./actions/nft/summarizeNftAttributes.js"; +import { getNftsForOwnerPages } from "./actions/nft/getNftsForOwnerPages.js"; +import { getNftsForContractPages } from "./actions/nft/getNftsForContractPages.js"; +import { getNftsForCollectionPages } from "./actions/nft/getNftsForCollectionPages.js"; +import { getContractsForOwnerPages } from "./actions/nft/getContractsForOwnerPages.js"; +import { getCollectionsForOwnerPages } from "./actions/nft/getCollectionsForOwnerPages.js"; +import { getNftSalesPages } from "./actions/nft/getNftSalesPages.js"; import { getTokenBalances } from "./actions/token/getTokenBalances.js"; import { getTokenMetadata } from "./actions/token/getTokenMetadata.js"; import { getTokenAllowance } from "./actions/token/getTokenAllowance.js"; import { getAssetTransfers } from "./actions/transfers/getAssetTransfers.js"; +import { getAssetTransfersPages } from "./actions/transfers/getAssetTransfersPages.js"; type Action = ( params: Params, @@ -45,6 +55,11 @@ type Action = ( type RpcAction = (params: Params) => Promise; +type PagesAction = ( + params: Params, + options?: PaginateOptions, +) => AsyncGenerator; + /** The namespaced Data API actions attached by the {@link dataActions} decorator. */ export type DataActions = { portfolio: { @@ -64,6 +79,14 @@ export type DataActions = { T.GetNftContractsByAddressParams, T.GetNftContractsByAddressResult >; + getNftsByAddressPages: PagesAction< + T.GetNftsByAddressParams, + T.GetNftsByAddressResult + >; + getNftContractsByAddressPages: PagesAction< + T.GetNftContractsByAddressParams, + T.GetNftContractsByAddressResult + >; }; prices: { getTokenPricesBySymbol: Action< @@ -140,6 +163,27 @@ export type DataActions = { T.SummarizeNftAttributesParams, T.SummarizeNftAttributesResult >; + getNftsForOwnerPages: PagesAction< + T.GetNftsForOwnerParams, + T.GetNftsForOwnerResult + >; + getNftsForContractPages: PagesAction< + T.GetNftsForContractParams, + T.GetNftsForContractResult + >; + getNftsForCollectionPages: PagesAction< + T.GetNftsForCollectionParams, + T.GetNftsForCollectionResult + >; + getContractsForOwnerPages: PagesAction< + T.GetContractsForOwnerParams, + T.GetContractsForOwnerResult + >; + getCollectionsForOwnerPages: PagesAction< + T.GetCollectionsForOwnerParams, + T.GetCollectionsForOwnerResult + >; + getNftSalesPages: PagesAction; }; token: { getTokenBalances: RpcAction< @@ -160,6 +204,10 @@ export type DataActions = { T.GetAssetTransfersParams, T.GetAssetTransfersResult >; + getAssetTransfersPages: PagesAction< + T.GetAssetTransfersParams, + T.GetAssetTransfersResult + >; }; }; @@ -196,6 +244,10 @@ export function dataActions(client: DataClient): DataActions { getNftsByAddress(client, params, options), getNftContractsByAddress: (params, options) => getNftContractsByAddress(client, params, options), + getNftsByAddressPages: (params, options) => + getNftsByAddressPages(client, params, options), + getNftContractsByAddressPages: (params, options) => + getNftContractsByAddressPages(client, params, options), }, prices: { getTokenPricesBySymbol: (params, options) => @@ -246,6 +298,18 @@ export function dataActions(client: DataClient): DataActions { computeRarity(client, params, options), summarizeNftAttributes: (params, options) => summarizeNftAttributes(client, params, options), + getNftsForOwnerPages: (params, options) => + getNftsForOwnerPages(client, params, options), + getNftsForContractPages: (params, options) => + getNftsForContractPages(client, params, options), + getNftsForCollectionPages: (params, options) => + getNftsForCollectionPages(client, params, options), + getContractsForOwnerPages: (params, options) => + getContractsForOwnerPages(client, params, options), + getCollectionsForOwnerPages: (params, options) => + getCollectionsForOwnerPages(client, params, options), + getNftSalesPages: (params, options) => + getNftSalesPages(client, params, options), }, token: { getTokenBalances: (params) => getTokenBalances(client, params), @@ -254,6 +318,8 @@ export function dataActions(client: DataClient): DataActions { }, transfers: { getAssetTransfers: (params) => getAssetTransfers(client, params), + getAssetTransfersPages: (params, options) => + getAssetTransfersPages(client, params, options), }, }; } diff --git a/packages/data-apis/src/index.ts b/packages/data-apis/src/index.ts index 761cbffb7f..d815e9895b 100644 --- a/packages/data-apis/src/index.ts +++ b/packages/data-apis/src/index.ts @@ -8,12 +8,15 @@ export { dataActions } from "./decorator.js"; // per-request options export type { RequestOptions } from "./internal/clientHelpers.js"; +export type { PaginateOptions } from "./internal/paginate.js"; // actions (individually importable for tree-shaking / composability) export { getTokensByAddress } from "./actions/portfolio/getTokensByAddress.js"; export { getTokenBalancesByAddress } from "./actions/portfolio/getTokenBalancesByAddress.js"; export { getNftsByAddress } from "./actions/portfolio/getNftsByAddress.js"; export { getNftContractsByAddress } from "./actions/portfolio/getNftContractsByAddress.js"; +export { getNftsByAddressPages } from "./actions/portfolio/getNftsByAddressPages.js"; +export { getNftContractsByAddressPages } from "./actions/portfolio/getNftContractsByAddressPages.js"; export { getTokenPricesBySymbol } from "./actions/prices/getTokenPricesBySymbol.js"; export { getTokenPricesByAddress } from "./actions/prices/getTokenPricesByAddress.js"; export { getHistoricalTokenPrices } from "./actions/prices/getHistoricalTokenPrices.js"; @@ -38,10 +41,17 @@ export { isAirdropNft } from "./actions/nft/isAirdropNft.js"; export { isHolderOfContract } from "./actions/nft/isHolderOfContract.js"; export { computeRarity } from "./actions/nft/computeRarity.js"; export { summarizeNftAttributes } from "./actions/nft/summarizeNftAttributes.js"; +export { getNftsForOwnerPages } from "./actions/nft/getNftsForOwnerPages.js"; +export { getNftsForContractPages } from "./actions/nft/getNftsForContractPages.js"; +export { getNftsForCollectionPages } from "./actions/nft/getNftsForCollectionPages.js"; +export { getContractsForOwnerPages } from "./actions/nft/getContractsForOwnerPages.js"; +export { getCollectionsForOwnerPages } from "./actions/nft/getCollectionsForOwnerPages.js"; +export { getNftSalesPages } from "./actions/nft/getNftSalesPages.js"; export { getTokenBalances } from "./actions/token/getTokenBalances.js"; export { getTokenMetadata } from "./actions/token/getTokenMetadata.js"; export { getTokenAllowance } from "./actions/token/getTokenAllowance.js"; export { getAssetTransfers } from "./actions/transfers/getAssetTransfers.js"; +export { getAssetTransfersPages } from "./actions/transfers/getAssetTransfersPages.js"; // schemas export type { DataRpcSchema } from "./schema/rpc.js"; diff --git a/packages/data-apis/src/internal/errors.test.ts b/packages/data-apis/src/internal/errors.test.ts new file mode 100644 index 0000000000..90624df8b8 --- /dev/null +++ b/packages/data-apis/src/internal/errors.test.ts @@ -0,0 +1,67 @@ +import { AlchemyApiError } from "@alchemy/common"; +import { HttpRequestError, RpcRequestError } from "viem"; +import { describe, expect, it } from "vitest"; +import { redactUrlCredentials, wrapRpcError } from "./errors.js"; + +const SECRET = "supersecretapikey123"; + +describe("redactUrlCredentials", () => { + it("redacts /v2/ path segments and apiKey query params", () => { + expect( + redactUrlCredentials( + `https://eth-mainnet.g.alchemy.com/v2/${SECRET} and https://x.test/?apiKey=${SECRET}&y=1`, + ), + ).toBe( + "https://eth-mainnet.g.alchemy.com/v2/[redacted] and https://x.test/?apiKey=[redacted]&y=1", + ); + }); +}); + +describe("wrapRpcError", () => { + it("maps RpcRequestError to AlchemyApiError with the rpc code, redacted", () => { + const viemError = new RpcRequestError({ + body: { method: "alchemy_getAssetTransfers" }, + url: `https://eth-mainnet.g.alchemy.com/v2/${SECRET}`, + error: { code: -32602, message: "invalid params" }, + }); + const wrapped = (() => { + try { + wrapRpcError(viemError); + } catch (e) { + return e as AlchemyApiError; + } + throw new Error("did not throw"); + })(); + expect(wrapped).toBeInstanceOf(AlchemyApiError); + expect(wrapped.code).toBe(-32602); + expect(wrapped.message).not.toContain(SECRET); + }); + + it("maps HttpRequestError to AlchemyApiError with the status, redacted", () => { + const viemError = new HttpRequestError({ + url: `https://eth-mainnet.g.alchemy.com/v2/${SECRET}`, + status: 503, + details: `service unavailable at /v2/${SECRET}`, + }); + const wrapped = (() => { + try { + wrapRpcError(viemError); + } catch (e) { + return e as AlchemyApiError; + } + throw new Error("did not throw"); + })(); + expect(wrapped).toBeInstanceOf(AlchemyApiError); + expect(wrapped.status).toBe(503); + expect(wrapped.message).not.toContain(SECRET); + expect(JSON.stringify(wrapped)).not.toContain(SECRET); + }); + + it("passes AlchemyApiError and unknown errors through untouched", () => { + const original = new AlchemyApiError("already normalized", { status: 400 }); + expect(() => wrapRpcError(original)).toThrow(original); + + const unknown = new Error("not a viem error"); + expect(() => wrapRpcError(unknown)).toThrow(unknown); + }); +}); diff --git a/packages/data-apis/src/internal/errors.ts b/packages/data-apis/src/internal/errors.ts new file mode 100644 index 0000000000..81f27a052e --- /dev/null +++ b/packages/data-apis/src/internal/errors.ts @@ -0,0 +1,46 @@ +import { AlchemyApiError } from "@alchemy/common"; +import { HttpRequestError, RpcRequestError } from "viem"; + +/** + * Redacts credentials that can appear in URLs: keys embedded in "/v2/" + * RPC paths (when a caller configured a key-bearing url) and apiKey query + * params. The header-auth paths never put keys in URLs; this protects the + * configured-url escape hatch. + * + * @param {string} text Any error text that may embed a URL + * @returns {string} The text with credentials replaced by "[redacted]" + */ +export function redactUrlCredentials(text: string): string { + return text + .replace(/(\/v2\/)[A-Za-z0-9_-]+/g, "$1[redacted]") + .replace(/([?&]apiKey=)[^&\s]+/gi, "$1[redacted]"); +} + +/** + * Normalizes viem JSON-RPC failures into the {@link AlchemyApiError} family + * (the REST channel is normalized inside AlchemyRestClient), so consumers + * handle one error shape across both channels. URL-bearing viem errors are + * carried as redacted details rather than as a cause, so credential-bearing + * URLs never leak through error chains. + * + * @param {unknown} error The error thrown by `client.request` + * @returns {never} Always throws + */ +export function wrapRpcError(error: unknown): never { + if (error instanceof AlchemyApiError) { + throw error; + } + if (error instanceof RpcRequestError) { + throw new AlchemyApiError(redactUrlCredentials(error.shortMessage), { + code: error.code, + details: redactUrlCredentials(error.details), + }); + } + if (error instanceof HttpRequestError) { + throw new AlchemyApiError(redactUrlCredentials(error.shortMessage), { + status: error.status, + details: redactUrlCredentials(error.details ?? ""), + }); + } + throw error; +} diff --git a/packages/data-apis/src/internal/paginate.test.ts b/packages/data-apis/src/internal/paginate.test.ts new file mode 100644 index 0000000000..19ea4739e6 --- /dev/null +++ b/packages/data-apis/src/internal/paginate.test.ts @@ -0,0 +1,104 @@ +import { describe, expect, it, vi } from "vitest"; +import { paginate } from "./paginate.js"; + +type Page = { items: number[]; pageKey?: string }; + +const collect = async (gen: AsyncGenerator) => { + const pages: Page[] = []; + for await (const page of gen) pages.push(page); + return pages; +}; + +describe("paginate", () => { + it("walks cursors until the response omits one", async () => { + const fetchPage = vi + .fn<(cursor: string | undefined) => Promise>() + .mockResolvedValueOnce({ items: [1], pageKey: "a" }) + .mockResolvedValueOnce({ items: [2], pageKey: "b" }) + .mockResolvedValueOnce({ items: [3] }); + const pages = await collect( + paginate({ fetchPage, nextCursor: (p) => p.pageKey }), + ); + expect(pages.map((p) => p.items[0])).toEqual([1, 2, 3]); + expect(fetchPage.mock.calls.map((c) => c[0])).toEqual([ + undefined, + "a", + "b", + ]); + }); + + it("stops on an empty-string cursor", async () => { + const fetchPage = vi + .fn<(cursor: string | undefined) => Promise>() + .mockResolvedValue({ items: [1], pageKey: "" }); + const pages = await collect( + paginate({ fetchPage, nextCursor: (p) => p.pageKey }), + ); + expect(pages).toHaveLength(1); + }); + + it("throws on a repeated cursor instead of looping forever", async () => { + const fetchPage = vi + .fn<(cursor: string | undefined) => Promise>() + .mockResolvedValue({ items: [1], pageKey: "same" }); + await expect( + collect(paginate({ fetchPage, nextCursor: (p) => p.pageKey })), + ).rejects.toThrow(/repeated/); + expect(fetchPage).toHaveBeenCalledTimes(2); + }); + + it("respects maxPages, yielding the capping page", async () => { + const fetchPage = vi + .fn<(cursor: string | undefined) => Promise>() + .mockImplementation(async (cursor) => ({ + items: [Number(cursor ?? 0)], + pageKey: String(Number(cursor ?? 0) + 1), + })); + const pages = await collect( + paginate({ + fetchPage, + nextCursor: (p) => p.pageKey, + options: { maxPages: 3 }, + }), + ); + expect(pages).toHaveLength(3); + expect(fetchPage).toHaveBeenCalledTimes(3); + }); + + it("stops cleanly when the consumer breaks", async () => { + const fetchPage = vi + .fn<(cursor: string | undefined) => Promise>() + .mockImplementation(async (cursor) => ({ + items: [1], + pageKey: String(Number(cursor ?? 0) + 1), + })); + for await (const page of paginate({ + fetchPage, + nextCursor: (p) => p.pageKey, + })) { + void page; + break; + } + expect(fetchPage).toHaveBeenCalledTimes(1); + }); + + it("throws the abort reason when the signal aborts between pages", async () => { + const controller = new AbortController(); + const fetchPage = vi + .fn<(cursor: string | undefined) => Promise>() + .mockImplementation(async () => { + controller.abort(new Error("stop-now")); + return { items: [1], pageKey: "next" }; + }); + await expect( + collect( + paginate({ + fetchPage, + nextCursor: (p) => p.pageKey, + options: { signal: controller.signal }, + }), + ), + ).rejects.toThrow("stop-now"); + expect(fetchPage).toHaveBeenCalledTimes(1); + }); +}); diff --git a/packages/data-apis/src/internal/paginate.ts b/packages/data-apis/src/internal/paginate.ts new file mode 100644 index 0000000000..58f8c3e243 --- /dev/null +++ b/packages/data-apis/src/internal/paginate.ts @@ -0,0 +1,55 @@ +import { BaseError } from "@alchemy/common"; + +/** Options accepted by the `*Pages` async-iterator actions. */ +export type PaginateOptions = { + /** Aborts iteration (checked between pages and passed to page requests). */ + signal?: AbortSignal; + /** Stop after this many pages (the page that hits the cap is still yielded). */ + maxPages?: number; +}; + +/** + * Shared cursor-pagination driver behind the `*Pages` actions. Yields whole + * pages (page-level metadata like totalCount/validAt stays available; + * per-item iteration is one inner loop away). Stops on a missing or empty + * cursor, and throws if the server ever repeats a cursor — the guard against + * infinite pagination loops. + * + * @param {object} config The pagination wiring + * @param {Function} config.fetchPage Fetches one page for a cursor (undefined = first page) + * @param {Function} config.nextCursor Extracts the next cursor from a page + * @param {PaginateOptions} [config.options] Abort signal and page cap + * @returns {AsyncGenerator} Pages, in order + * @yields Each page result as returned by fetchPage + */ +export async function* paginate({ + fetchPage, + nextCursor, + options, +}: { + fetchPage: ( + cursor: string | undefined, + signal?: AbortSignal, + ) => Promise; + nextCursor: (page: TPage) => string | null | undefined; + options?: PaginateOptions; +}): AsyncGenerator { + const seen = new Set(); + let cursor: string | undefined; + let pages = 0; + while (true) { + options?.signal?.throwIfAborted(); + const page = await fetchPage(cursor, options?.signal); + yield page; + if (options?.maxPages != null && ++pages >= options.maxPages) return; + const next = nextCursor(page); + if (next == null || next === "") return; + if (seen.has(next)) { + throw new BaseError( + `Pagination cursor "${next}" was repeated by the server; stopping to avoid an infinite loop.`, + ); + } + seen.add(next); + cursor = next; + } +} From 4fc0591ce79b1ff83eff4701d86bcd0392e0a92f Mon Sep 17 00:00:00 2001 From: blake duncan Date: Wed, 10 Jun 2026 11:10:09 -0400 Subject: [PATCH 6/8] =?UTF-8?q?feat(data-apis):=20publish=20readiness=20?= =?UTF-8?q?=E2=80=94=20alpha=20versioning,=20typedoc,=20README?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - version 5.0.3-alpha.0 with publishConfig.tag 'alpha'; deliberately NOT in lerna.json's fixed-version publish set so the regular release can't ship it as latest — alpha publishing + graduation checklist documented in the README - typedoc: data-apis entry point + tsconfig.typedoc include + nav registration in generate-typedoc-yaml.ts; generated reference docs committed under docs/pages/reference/data-apis (CI's docs:sdk drift check now covers the package) - README rewritten: install, both entry points, per-namespace quickstart, three network formats, pagination, error semantics, release process Co-Authored-By: Claude Fable 5 --- docs/docs.yml | 287 ++++++++++ docs/pages/reference/common/src/README.mdx | 77 +-- .../common/src/classes/AlchemyApiError.mdx | 219 ++++++++ .../common/src/classes/AlchemyRestClient.mdx | 115 ++++ .../common/src/classes/BaseError.mdx | 3 +- .../common/src/classes/FetchError.mdx | 108 +++- .../common/src/classes/ServerError.mdx | 108 +++- .../common/src/functions/composeSignals.mdx | 52 ++ .../common/src/functions/resolveNetwork.mdx | 63 +++ .../reference/common/src/functions/sleep.mdx | 66 +++ .../type-aliases/AlchemyApiErrorDetails.mdx | 87 ++++ .../src/type-aliases/AlchemyNetwork.mdx | 18 + .../type-aliases/AlchemyRestClientParams.mdx | 129 +++++ .../src/type-aliases/KnownAlchemyNetwork.mdx | 32 ++ .../common/src/type-aliases/NetworkInput.mdx | 18 + .../common/src/type-aliases/QueryParams.mdx | 16 + .../common/src/type-aliases/QueryValue.mdx | 16 + .../src/type-aliases/ResolvedNetwork.mdx | 51 ++ .../common/src/type-aliases/RestRequestFn.mdx | 104 ++++ .../src/type-aliases/RestRequestOptions.mdx | 87 ++++ .../src/type-aliases/RestRequestParams.mdx | 38 ++ .../src/type-aliases/RestRequestSchema.mdx | 14 + docs/pages/reference/data-apis/src/README.mdx | 204 ++++++++ .../data-apis/src/functions/computeRarity.mdx | 89 ++++ .../src/functions/createDataClient.mdx | 67 +++ .../data-apis/src/functions/dataActions.mdx | 68 +++ .../src/functions/getAssetTransfers.mdx | 80 +++ .../src/functions/getAssetTransfersPages.mdx | 97 ++++ .../src/functions/getCollectionMetadata.mdx | 109 ++++ .../src/functions/getCollectionsForOwner.mdx | 93 ++++ .../functions/getCollectionsForOwnerPages.mdx | 97 ++++ .../src/functions/getContractMetadata.mdx | 129 +++++ .../functions/getContractMetadataBatch.mdx | 81 +++ .../src/functions/getContractsForOwner.mdx | 93 ++++ .../functions/getContractsForOwnerPages.mdx | 97 ++++ .../data-apis/src/functions/getFloorPrice.mdx | 101 ++++ .../functions/getHistoricalTokenPrices.mdx | 109 ++++ .../functions/getNftContractsByAddress.mdx | 98 ++++ .../getNftContractsByAddressPages.mdx | 101 ++++ .../src/functions/getNftMetadata.mdx | 231 +++++++++ .../src/functions/getNftMetadataBatch.mdx | 81 +++ .../data-apis/src/functions/getNftSales.mdx | 101 ++++ .../src/functions/getNftSalesPages.mdx | 105 ++++ .../src/functions/getNftsByAddress.mdx | 98 ++++ .../src/functions/getNftsByAddressPages.mdx | 101 ++++ .../src/functions/getNftsForCollection.mdx | 91 ++++ .../functions/getNftsForCollectionPages.mdx | 95 ++++ .../src/functions/getNftsForContract.mdx | 91 ++++ .../src/functions/getNftsForContractPages.mdx | 95 ++++ .../src/functions/getNftsForOwner.mdx | 103 ++++ .../src/functions/getNftsForOwnerPages.mdx | 107 ++++ .../src/functions/getOwnersForContract.mdx | 89 ++++ .../src/functions/getOwnersForNft.mdx | 91 ++++ .../src/functions/getSpamContracts.mdx | 89 ++++ .../src/functions/getTokenAllowance.mdx | 68 +++ .../src/functions/getTokenBalances.mdx | 71 +++ .../functions/getTokenBalancesByAddress.mdx | 96 ++++ .../src/functions/getTokenMetadata.mdx | 71 +++ .../src/functions/getTokenPricesByAddress.mdx | 89 ++++ .../src/functions/getTokenPricesBySymbol.mdx | 105 ++++ .../src/functions/getTokensByAddress.mdx | 108 ++++ .../data-apis/src/functions/isAirdropNft.mdx | 89 ++++ .../src/functions/isHolderOfContract.mdx | 89 ++++ .../src/functions/isSpamContract.mdx | 89 ++++ .../src/functions/searchContractMetadata.mdx | 81 +++ .../src/functions/summarizeNftAttributes.mdx | 93 ++++ .../src/interfaces/PortfolioAddressEntry.mdx | 55 ++ .../src/interfaces/PriceAddressEntry.mdx | 55 ++ .../src/type-aliases/AlchemyDataClient.mdx | 15 + .../type-aliases/AlchemyDataClientOptions.mdx | 50 ++ .../src/type-aliases/AssetTransfer.mdx | 14 + .../src/type-aliases/ComputeRarityParams.mdx | 14 + .../src/type-aliases/ComputeRarityResult.mdx | 14 + .../src/type-aliases/DataActions.mdx | 490 ++++++++++++++++++ .../src/type-aliases/DataRpcSchema.mdx | 28 + .../type-aliases/GetAssetTransfersParams.mdx | 45 ++ .../type-aliases/GetAssetTransfersResult.mdx | 18 + .../GetCollectionMetadataParams.mdx | 14 + .../GetCollectionMetadataResult.mdx | 14 + .../GetCollectionsForOwnerParams.mdx | 14 + .../GetCollectionsForOwnerResult.mdx | 14 + .../GetContractMetadataBatchParams.mdx | 43 ++ .../GetContractMetadataBatchResult.mdx | 14 + .../GetContractMetadataParams.mdx | 14 + .../GetContractMetadataResult.mdx | 14 + .../GetContractsForOwnerParams.mdx | 14 + .../GetContractsForOwnerResult.mdx | 14 + .../src/type-aliases/GetFloorPriceParams.mdx | 14 + .../src/type-aliases/GetFloorPriceResult.mdx | 14 + .../GetHistoricalTokenPricesParams.mdx | 15 + .../GetHistoricalTokenPricesResult.mdx | 14 + .../GetNftContractsByAddressParams.mdx | 15 + .../GetNftContractsByAddressResult.mdx | 14 + .../GetNftMetadataBatchParams.mdx | 43 ++ .../GetNftMetadataBatchResult.mdx | 14 + .../src/type-aliases/GetNftMetadataParams.mdx | 14 + .../src/type-aliases/GetNftMetadataResult.mdx | 14 + .../src/type-aliases/GetNftSalesParams.mdx | 14 + .../src/type-aliases/GetNftSalesResult.mdx | 14 + .../type-aliases/GetNftsByAddressParams.mdx | 14 + .../type-aliases/GetNftsByAddressResult.mdx | 14 + .../GetNftsForCollectionParams.mdx | 14 + .../GetNftsForCollectionResult.mdx | 14 + .../type-aliases/GetNftsForContractParams.mdx | 14 + .../type-aliases/GetNftsForContractResult.mdx | 14 + .../type-aliases/GetNftsForOwnerParams.mdx | 14 + .../type-aliases/GetNftsForOwnerResult.mdx | 14 + .../GetOwnersForContractParams.mdx | 14 + .../GetOwnersForContractResult.mdx | 14 + .../type-aliases/GetOwnersForNftParams.mdx | 14 + .../type-aliases/GetOwnersForNftResult.mdx | 14 + .../type-aliases/GetSpamContractsParams.mdx | 43 ++ .../type-aliases/GetSpamContractsResult.mdx | 14 + .../type-aliases/GetTokenAllowanceParams.mdx | 43 ++ .../type-aliases/GetTokenAllowanceResult.mdx | 14 + .../GetTokenBalancesByAddressParams.mdx | 15 + .../GetTokenBalancesByAddressResult.mdx | 14 + .../type-aliases/GetTokenBalancesParams.mdx | 85 +++ .../type-aliases/GetTokenBalancesResult.mdx | 14 + .../type-aliases/GetTokenMetadataParams.mdx | 57 ++ .../type-aliases/GetTokenMetadataResult.mdx | 14 + .../GetTokenPricesByAddressParams.mdx | 42 ++ .../GetTokenPricesByAddressResult.mdx | 14 + .../GetTokenPricesBySymbolParams.mdx | 16 + .../GetTokenPricesBySymbolResult.mdx | 14 + .../type-aliases/GetTokensByAddressParams.mdx | 14 + .../type-aliases/GetTokensByAddressResult.mdx | 14 + .../src/type-aliases/IsAirdropNftParams.mdx | 14 + .../src/type-aliases/IsAirdropNftResult.mdx | 14 + .../type-aliases/IsHolderOfContractParams.mdx | 14 + .../type-aliases/IsHolderOfContractResult.mdx | 14 + .../src/type-aliases/IsSpamContractParams.mdx | 14 + .../src/type-aliases/IsSpamContractResult.mdx | 14 + .../src/type-aliases/NftRestSchema.mdx | 164 ++++++ .../src/type-aliases/PaginateOptions.mdx | 59 +++ .../src/type-aliases/PortfolioRestSchema.mdx | 45 ++ .../src/type-aliases/PortfolioToken.mdx | 16 + .../src/type-aliases/PricesRestSchema.mdx | 38 ++ .../src/type-aliases/RequestOptions.mdx | 45 ++ .../SearchContractMetadataParams.mdx | 14 + .../SearchContractMetadataResult.mdx | 14 + .../SummarizeNftAttributesParams.mdx | 14 + .../SummarizeNftAttributesResult.mdx | 14 + .../data-apis/src/variables/VERSION.mdx | 14 + docs/pages/reference/modules.mdx | 1 + packages/data-apis/README.md | 131 +++-- packages/data-apis/package.json | 16 +- packages/data-apis/src/version.ts | 2 +- scripts/generate-typedoc-yaml.ts | 2 + tsconfig.typedoc.json | 1 + typedoc.json | 1 + 151 files changed, 8397 insertions(+), 77 deletions(-) create mode 100644 docs/pages/reference/common/src/classes/AlchemyApiError.mdx create mode 100644 docs/pages/reference/common/src/classes/AlchemyRestClient.mdx create mode 100644 docs/pages/reference/common/src/functions/composeSignals.mdx create mode 100644 docs/pages/reference/common/src/functions/resolveNetwork.mdx create mode 100644 docs/pages/reference/common/src/functions/sleep.mdx create mode 100644 docs/pages/reference/common/src/type-aliases/AlchemyApiErrorDetails.mdx create mode 100644 docs/pages/reference/common/src/type-aliases/AlchemyNetwork.mdx create mode 100644 docs/pages/reference/common/src/type-aliases/AlchemyRestClientParams.mdx create mode 100644 docs/pages/reference/common/src/type-aliases/KnownAlchemyNetwork.mdx create mode 100644 docs/pages/reference/common/src/type-aliases/NetworkInput.mdx create mode 100644 docs/pages/reference/common/src/type-aliases/QueryParams.mdx create mode 100644 docs/pages/reference/common/src/type-aliases/QueryValue.mdx create mode 100644 docs/pages/reference/common/src/type-aliases/ResolvedNetwork.mdx create mode 100644 docs/pages/reference/common/src/type-aliases/RestRequestFn.mdx create mode 100644 docs/pages/reference/common/src/type-aliases/RestRequestOptions.mdx create mode 100644 docs/pages/reference/common/src/type-aliases/RestRequestParams.mdx create mode 100644 docs/pages/reference/common/src/type-aliases/RestRequestSchema.mdx create mode 100644 docs/pages/reference/data-apis/src/README.mdx create mode 100644 docs/pages/reference/data-apis/src/functions/computeRarity.mdx create mode 100644 docs/pages/reference/data-apis/src/functions/createDataClient.mdx create mode 100644 docs/pages/reference/data-apis/src/functions/dataActions.mdx create mode 100644 docs/pages/reference/data-apis/src/functions/getAssetTransfers.mdx create mode 100644 docs/pages/reference/data-apis/src/functions/getAssetTransfersPages.mdx create mode 100644 docs/pages/reference/data-apis/src/functions/getCollectionMetadata.mdx create mode 100644 docs/pages/reference/data-apis/src/functions/getCollectionsForOwner.mdx create mode 100644 docs/pages/reference/data-apis/src/functions/getCollectionsForOwnerPages.mdx create mode 100644 docs/pages/reference/data-apis/src/functions/getContractMetadata.mdx create mode 100644 docs/pages/reference/data-apis/src/functions/getContractMetadataBatch.mdx create mode 100644 docs/pages/reference/data-apis/src/functions/getContractsForOwner.mdx create mode 100644 docs/pages/reference/data-apis/src/functions/getContractsForOwnerPages.mdx create mode 100644 docs/pages/reference/data-apis/src/functions/getFloorPrice.mdx create mode 100644 docs/pages/reference/data-apis/src/functions/getHistoricalTokenPrices.mdx create mode 100644 docs/pages/reference/data-apis/src/functions/getNftContractsByAddress.mdx create mode 100644 docs/pages/reference/data-apis/src/functions/getNftContractsByAddressPages.mdx create mode 100644 docs/pages/reference/data-apis/src/functions/getNftMetadata.mdx create mode 100644 docs/pages/reference/data-apis/src/functions/getNftMetadataBatch.mdx create mode 100644 docs/pages/reference/data-apis/src/functions/getNftSales.mdx create mode 100644 docs/pages/reference/data-apis/src/functions/getNftSalesPages.mdx create mode 100644 docs/pages/reference/data-apis/src/functions/getNftsByAddress.mdx create mode 100644 docs/pages/reference/data-apis/src/functions/getNftsByAddressPages.mdx create mode 100644 docs/pages/reference/data-apis/src/functions/getNftsForCollection.mdx create mode 100644 docs/pages/reference/data-apis/src/functions/getNftsForCollectionPages.mdx create mode 100644 docs/pages/reference/data-apis/src/functions/getNftsForContract.mdx create mode 100644 docs/pages/reference/data-apis/src/functions/getNftsForContractPages.mdx create mode 100644 docs/pages/reference/data-apis/src/functions/getNftsForOwner.mdx create mode 100644 docs/pages/reference/data-apis/src/functions/getNftsForOwnerPages.mdx create mode 100644 docs/pages/reference/data-apis/src/functions/getOwnersForContract.mdx create mode 100644 docs/pages/reference/data-apis/src/functions/getOwnersForNft.mdx create mode 100644 docs/pages/reference/data-apis/src/functions/getSpamContracts.mdx create mode 100644 docs/pages/reference/data-apis/src/functions/getTokenAllowance.mdx create mode 100644 docs/pages/reference/data-apis/src/functions/getTokenBalances.mdx create mode 100644 docs/pages/reference/data-apis/src/functions/getTokenBalancesByAddress.mdx create mode 100644 docs/pages/reference/data-apis/src/functions/getTokenMetadata.mdx create mode 100644 docs/pages/reference/data-apis/src/functions/getTokenPricesByAddress.mdx create mode 100644 docs/pages/reference/data-apis/src/functions/getTokenPricesBySymbol.mdx create mode 100644 docs/pages/reference/data-apis/src/functions/getTokensByAddress.mdx create mode 100644 docs/pages/reference/data-apis/src/functions/isAirdropNft.mdx create mode 100644 docs/pages/reference/data-apis/src/functions/isHolderOfContract.mdx create mode 100644 docs/pages/reference/data-apis/src/functions/isSpamContract.mdx create mode 100644 docs/pages/reference/data-apis/src/functions/searchContractMetadata.mdx create mode 100644 docs/pages/reference/data-apis/src/functions/summarizeNftAttributes.mdx create mode 100644 docs/pages/reference/data-apis/src/interfaces/PortfolioAddressEntry.mdx create mode 100644 docs/pages/reference/data-apis/src/interfaces/PriceAddressEntry.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/AlchemyDataClient.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/AlchemyDataClientOptions.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/AssetTransfer.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/ComputeRarityParams.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/ComputeRarityResult.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/DataActions.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/DataRpcSchema.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/GetAssetTransfersParams.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/GetAssetTransfersResult.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/GetCollectionMetadataParams.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/GetCollectionMetadataResult.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/GetCollectionsForOwnerParams.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/GetCollectionsForOwnerResult.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/GetContractMetadataBatchParams.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/GetContractMetadataBatchResult.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/GetContractMetadataParams.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/GetContractMetadataResult.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/GetContractsForOwnerParams.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/GetContractsForOwnerResult.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/GetFloorPriceParams.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/GetFloorPriceResult.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/GetHistoricalTokenPricesParams.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/GetHistoricalTokenPricesResult.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/GetNftContractsByAddressParams.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/GetNftContractsByAddressResult.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/GetNftMetadataBatchParams.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/GetNftMetadataBatchResult.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/GetNftMetadataParams.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/GetNftMetadataResult.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/GetNftSalesParams.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/GetNftSalesResult.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/GetNftsByAddressParams.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/GetNftsByAddressResult.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/GetNftsForCollectionParams.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/GetNftsForCollectionResult.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/GetNftsForContractParams.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/GetNftsForContractResult.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/GetNftsForOwnerParams.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/GetNftsForOwnerResult.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/GetOwnersForContractParams.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/GetOwnersForContractResult.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/GetOwnersForNftParams.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/GetOwnersForNftResult.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/GetSpamContractsParams.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/GetSpamContractsResult.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/GetTokenAllowanceParams.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/GetTokenAllowanceResult.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/GetTokenBalancesByAddressParams.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/GetTokenBalancesByAddressResult.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/GetTokenBalancesParams.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/GetTokenBalancesResult.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/GetTokenMetadataParams.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/GetTokenMetadataResult.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/GetTokenPricesByAddressParams.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/GetTokenPricesByAddressResult.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/GetTokenPricesBySymbolParams.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/GetTokenPricesBySymbolResult.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/GetTokensByAddressParams.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/GetTokensByAddressResult.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/IsAirdropNftParams.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/IsAirdropNftResult.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/IsHolderOfContractParams.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/IsHolderOfContractResult.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/IsSpamContractParams.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/IsSpamContractResult.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/NftRestSchema.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/PaginateOptions.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/PortfolioRestSchema.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/PortfolioToken.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/PricesRestSchema.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/RequestOptions.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/SearchContractMetadataParams.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/SearchContractMetadataResult.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/SummarizeNftAttributesParams.mdx create mode 100644 docs/pages/reference/data-apis/src/type-aliases/SummarizeNftAttributesResult.mdx create mode 100644 docs/pages/reference/data-apis/src/variables/VERSION.mdx diff --git a/docs/docs.yml b/docs/docs.yml index 9d2c4bf6a5..534e6f7ed4 100644 --- a/docs/docs.yml +++ b/docs/docs.yml @@ -506,6 +506,259 @@ navigation: path: wallets/pages/reference/smart-accounts/src/variables/semiModularAccount7702StaticImpl.mdx - page: semiModularAccountV2StaticImpl path: wallets/pages/reference/smart-accounts/src/variables/semiModularAccountV2StaticImpl.mdx + - section: Data APIs + path: wallets/pages/reference/data-apis/src/README.mdx + contents: + - section: Functions + contents: + - page: computeRarity + path: wallets/pages/reference/data-apis/src/functions/computeRarity.mdx + - page: createDataClient + path: wallets/pages/reference/data-apis/src/functions/createDataClient.mdx + - page: dataActions + path: wallets/pages/reference/data-apis/src/functions/dataActions.mdx + - page: getAssetTransfers + path: wallets/pages/reference/data-apis/src/functions/getAssetTransfers.mdx + - page: getAssetTransfersPages + path: wallets/pages/reference/data-apis/src/functions/getAssetTransfersPages.mdx + - page: getCollectionMetadata + path: wallets/pages/reference/data-apis/src/functions/getCollectionMetadata.mdx + - page: getCollectionsForOwner + path: wallets/pages/reference/data-apis/src/functions/getCollectionsForOwner.mdx + - page: getCollectionsForOwnerPages + path: wallets/pages/reference/data-apis/src/functions/getCollectionsForOwnerPages.mdx + - page: getContractMetadata + path: wallets/pages/reference/data-apis/src/functions/getContractMetadata.mdx + - page: getContractMetadataBatch + path: wallets/pages/reference/data-apis/src/functions/getContractMetadataBatch.mdx + - page: getContractsForOwner + path: wallets/pages/reference/data-apis/src/functions/getContractsForOwner.mdx + - page: getContractsForOwnerPages + path: wallets/pages/reference/data-apis/src/functions/getContractsForOwnerPages.mdx + - page: getFloorPrice + path: wallets/pages/reference/data-apis/src/functions/getFloorPrice.mdx + - page: getHistoricalTokenPrices + path: wallets/pages/reference/data-apis/src/functions/getHistoricalTokenPrices.mdx + - page: getNftContractsByAddress + path: wallets/pages/reference/data-apis/src/functions/getNftContractsByAddress.mdx + - page: getNftContractsByAddressPages + path: wallets/pages/reference/data-apis/src/functions/getNftContractsByAddressPages.mdx + - page: getNftMetadata + path: wallets/pages/reference/data-apis/src/functions/getNftMetadata.mdx + - page: getNftMetadataBatch + path: wallets/pages/reference/data-apis/src/functions/getNftMetadataBatch.mdx + - page: getNftSales + path: wallets/pages/reference/data-apis/src/functions/getNftSales.mdx + - page: getNftSalesPages + path: wallets/pages/reference/data-apis/src/functions/getNftSalesPages.mdx + - page: getNftsByAddress + path: wallets/pages/reference/data-apis/src/functions/getNftsByAddress.mdx + - page: getNftsByAddressPages + path: wallets/pages/reference/data-apis/src/functions/getNftsByAddressPages.mdx + - page: getNftsForCollection + path: wallets/pages/reference/data-apis/src/functions/getNftsForCollection.mdx + - page: getNftsForCollectionPages + path: wallets/pages/reference/data-apis/src/functions/getNftsForCollectionPages.mdx + - page: getNftsForContract + path: wallets/pages/reference/data-apis/src/functions/getNftsForContract.mdx + - page: getNftsForContractPages + path: wallets/pages/reference/data-apis/src/functions/getNftsForContractPages.mdx + - page: getNftsForOwner + path: wallets/pages/reference/data-apis/src/functions/getNftsForOwner.mdx + - page: getNftsForOwnerPages + path: wallets/pages/reference/data-apis/src/functions/getNftsForOwnerPages.mdx + - page: getOwnersForContract + path: wallets/pages/reference/data-apis/src/functions/getOwnersForContract.mdx + - page: getOwnersForNft + path: wallets/pages/reference/data-apis/src/functions/getOwnersForNft.mdx + - page: getSpamContracts + path: wallets/pages/reference/data-apis/src/functions/getSpamContracts.mdx + - page: getTokenAllowance + path: wallets/pages/reference/data-apis/src/functions/getTokenAllowance.mdx + - page: getTokenBalances + path: wallets/pages/reference/data-apis/src/functions/getTokenBalances.mdx + - page: getTokenBalancesByAddress + path: wallets/pages/reference/data-apis/src/functions/getTokenBalancesByAddress.mdx + - page: getTokenMetadata + path: wallets/pages/reference/data-apis/src/functions/getTokenMetadata.mdx + - page: getTokenPricesByAddress + path: wallets/pages/reference/data-apis/src/functions/getTokenPricesByAddress.mdx + - page: getTokenPricesBySymbol + path: wallets/pages/reference/data-apis/src/functions/getTokenPricesBySymbol.mdx + - page: getTokensByAddress + path: wallets/pages/reference/data-apis/src/functions/getTokensByAddress.mdx + - page: isAirdropNft + path: wallets/pages/reference/data-apis/src/functions/isAirdropNft.mdx + - page: isHolderOfContract + path: wallets/pages/reference/data-apis/src/functions/isHolderOfContract.mdx + - page: isSpamContract + path: wallets/pages/reference/data-apis/src/functions/isSpamContract.mdx + - page: searchContractMetadata + path: wallets/pages/reference/data-apis/src/functions/searchContractMetadata.mdx + - page: summarizeNftAttributes + path: wallets/pages/reference/data-apis/src/functions/summarizeNftAttributes.mdx + - section: Interfaces + contents: + - page: PortfolioAddressEntry + path: wallets/pages/reference/data-apis/src/interfaces/PortfolioAddressEntry.mdx + - page: PriceAddressEntry + path: wallets/pages/reference/data-apis/src/interfaces/PriceAddressEntry.mdx + - section: Type Aliases + contents: + - page: AlchemyDataClient + path: wallets/pages/reference/data-apis/src/type-aliases/AlchemyDataClient.mdx + - page: AlchemyDataClientOptions + path: wallets/pages/reference/data-apis/src/type-aliases/AlchemyDataClientOptions.mdx + - page: AssetTransfer + path: wallets/pages/reference/data-apis/src/type-aliases/AssetTransfer.mdx + - page: ComputeRarityParams + path: wallets/pages/reference/data-apis/src/type-aliases/ComputeRarityParams.mdx + - page: ComputeRarityResult + path: wallets/pages/reference/data-apis/src/type-aliases/ComputeRarityResult.mdx + - page: DataActions + path: wallets/pages/reference/data-apis/src/type-aliases/DataActions.mdx + - page: DataRpcSchema + path: wallets/pages/reference/data-apis/src/type-aliases/DataRpcSchema.mdx + - page: GetAssetTransfersParams + path: wallets/pages/reference/data-apis/src/type-aliases/GetAssetTransfersParams.mdx + - page: GetAssetTransfersResult + path: wallets/pages/reference/data-apis/src/type-aliases/GetAssetTransfersResult.mdx + - page: GetCollectionMetadataParams + path: wallets/pages/reference/data-apis/src/type-aliases/GetCollectionMetadataParams.mdx + - page: GetCollectionMetadataResult + path: wallets/pages/reference/data-apis/src/type-aliases/GetCollectionMetadataResult.mdx + - page: GetCollectionsForOwnerParams + path: wallets/pages/reference/data-apis/src/type-aliases/GetCollectionsForOwnerParams.mdx + - page: GetCollectionsForOwnerResult + path: wallets/pages/reference/data-apis/src/type-aliases/GetCollectionsForOwnerResult.mdx + - page: GetContractMetadataBatchParams + path: wallets/pages/reference/data-apis/src/type-aliases/GetContractMetadataBatchParams.mdx + - page: GetContractMetadataBatchResult + path: wallets/pages/reference/data-apis/src/type-aliases/GetContractMetadataBatchResult.mdx + - page: GetContractMetadataParams + path: wallets/pages/reference/data-apis/src/type-aliases/GetContractMetadataParams.mdx + - page: GetContractMetadataResult + path: wallets/pages/reference/data-apis/src/type-aliases/GetContractMetadataResult.mdx + - page: GetContractsForOwnerParams + path: wallets/pages/reference/data-apis/src/type-aliases/GetContractsForOwnerParams.mdx + - page: GetContractsForOwnerResult + path: wallets/pages/reference/data-apis/src/type-aliases/GetContractsForOwnerResult.mdx + - page: GetFloorPriceParams + path: wallets/pages/reference/data-apis/src/type-aliases/GetFloorPriceParams.mdx + - page: GetFloorPriceResult + path: wallets/pages/reference/data-apis/src/type-aliases/GetFloorPriceResult.mdx + - page: GetHistoricalTokenPricesParams + path: wallets/pages/reference/data-apis/src/type-aliases/GetHistoricalTokenPricesParams.mdx + - page: GetHistoricalTokenPricesResult + path: wallets/pages/reference/data-apis/src/type-aliases/GetHistoricalTokenPricesResult.mdx + - page: GetNftContractsByAddressParams + path: wallets/pages/reference/data-apis/src/type-aliases/GetNftContractsByAddressParams.mdx + - page: GetNftContractsByAddressResult + path: wallets/pages/reference/data-apis/src/type-aliases/GetNftContractsByAddressResult.mdx + - page: GetNftMetadataBatchParams + path: wallets/pages/reference/data-apis/src/type-aliases/GetNftMetadataBatchParams.mdx + - page: GetNftMetadataBatchResult + path: wallets/pages/reference/data-apis/src/type-aliases/GetNftMetadataBatchResult.mdx + - page: GetNftMetadataParams + path: wallets/pages/reference/data-apis/src/type-aliases/GetNftMetadataParams.mdx + - page: GetNftMetadataResult + path: wallets/pages/reference/data-apis/src/type-aliases/GetNftMetadataResult.mdx + - page: GetNftSalesParams + path: wallets/pages/reference/data-apis/src/type-aliases/GetNftSalesParams.mdx + - page: GetNftSalesResult + path: wallets/pages/reference/data-apis/src/type-aliases/GetNftSalesResult.mdx + - page: GetNftsByAddressParams + path: wallets/pages/reference/data-apis/src/type-aliases/GetNftsByAddressParams.mdx + - page: GetNftsByAddressResult + path: wallets/pages/reference/data-apis/src/type-aliases/GetNftsByAddressResult.mdx + - page: GetNftsForCollectionParams + path: wallets/pages/reference/data-apis/src/type-aliases/GetNftsForCollectionParams.mdx + - page: GetNftsForCollectionResult + path: wallets/pages/reference/data-apis/src/type-aliases/GetNftsForCollectionResult.mdx + - page: GetNftsForContractParams + path: wallets/pages/reference/data-apis/src/type-aliases/GetNftsForContractParams.mdx + - page: GetNftsForContractResult + path: wallets/pages/reference/data-apis/src/type-aliases/GetNftsForContractResult.mdx + - page: GetNftsForOwnerParams + path: wallets/pages/reference/data-apis/src/type-aliases/GetNftsForOwnerParams.mdx + - page: GetNftsForOwnerResult + path: wallets/pages/reference/data-apis/src/type-aliases/GetNftsForOwnerResult.mdx + - page: GetOwnersForContractParams + path: wallets/pages/reference/data-apis/src/type-aliases/GetOwnersForContractParams.mdx + - page: GetOwnersForContractResult + path: wallets/pages/reference/data-apis/src/type-aliases/GetOwnersForContractResult.mdx + - page: GetOwnersForNftParams + path: wallets/pages/reference/data-apis/src/type-aliases/GetOwnersForNftParams.mdx + - page: GetOwnersForNftResult + path: wallets/pages/reference/data-apis/src/type-aliases/GetOwnersForNftResult.mdx + - page: GetSpamContractsParams + path: wallets/pages/reference/data-apis/src/type-aliases/GetSpamContractsParams.mdx + - page: GetSpamContractsResult + path: wallets/pages/reference/data-apis/src/type-aliases/GetSpamContractsResult.mdx + - page: GetTokenAllowanceParams + path: wallets/pages/reference/data-apis/src/type-aliases/GetTokenAllowanceParams.mdx + - page: GetTokenAllowanceResult + path: wallets/pages/reference/data-apis/src/type-aliases/GetTokenAllowanceResult.mdx + - page: GetTokenBalancesByAddressParams + path: wallets/pages/reference/data-apis/src/type-aliases/GetTokenBalancesByAddressParams.mdx + - page: GetTokenBalancesByAddressResult + path: wallets/pages/reference/data-apis/src/type-aliases/GetTokenBalancesByAddressResult.mdx + - page: GetTokenBalancesParams + path: wallets/pages/reference/data-apis/src/type-aliases/GetTokenBalancesParams.mdx + - page: GetTokenBalancesResult + path: wallets/pages/reference/data-apis/src/type-aliases/GetTokenBalancesResult.mdx + - page: GetTokenMetadataParams + path: wallets/pages/reference/data-apis/src/type-aliases/GetTokenMetadataParams.mdx + - page: GetTokenMetadataResult + path: wallets/pages/reference/data-apis/src/type-aliases/GetTokenMetadataResult.mdx + - page: GetTokenPricesByAddressParams + path: wallets/pages/reference/data-apis/src/type-aliases/GetTokenPricesByAddressParams.mdx + - page: GetTokenPricesByAddressResult + path: wallets/pages/reference/data-apis/src/type-aliases/GetTokenPricesByAddressResult.mdx + - page: GetTokenPricesBySymbolParams + path: wallets/pages/reference/data-apis/src/type-aliases/GetTokenPricesBySymbolParams.mdx + - page: GetTokenPricesBySymbolResult + path: wallets/pages/reference/data-apis/src/type-aliases/GetTokenPricesBySymbolResult.mdx + - page: GetTokensByAddressParams + path: wallets/pages/reference/data-apis/src/type-aliases/GetTokensByAddressParams.mdx + - page: GetTokensByAddressResult + path: wallets/pages/reference/data-apis/src/type-aliases/GetTokensByAddressResult.mdx + - page: IsAirdropNftParams + path: wallets/pages/reference/data-apis/src/type-aliases/IsAirdropNftParams.mdx + - page: IsAirdropNftResult + path: wallets/pages/reference/data-apis/src/type-aliases/IsAirdropNftResult.mdx + - page: IsHolderOfContractParams + path: wallets/pages/reference/data-apis/src/type-aliases/IsHolderOfContractParams.mdx + - page: IsHolderOfContractResult + path: wallets/pages/reference/data-apis/src/type-aliases/IsHolderOfContractResult.mdx + - page: IsSpamContractParams + path: wallets/pages/reference/data-apis/src/type-aliases/IsSpamContractParams.mdx + - page: IsSpamContractResult + path: wallets/pages/reference/data-apis/src/type-aliases/IsSpamContractResult.mdx + - page: NftRestSchema + path: wallets/pages/reference/data-apis/src/type-aliases/NftRestSchema.mdx + - page: PaginateOptions + path: wallets/pages/reference/data-apis/src/type-aliases/PaginateOptions.mdx + - page: PortfolioRestSchema + path: wallets/pages/reference/data-apis/src/type-aliases/PortfolioRestSchema.mdx + - page: PortfolioToken + path: wallets/pages/reference/data-apis/src/type-aliases/PortfolioToken.mdx + - page: PricesRestSchema + path: wallets/pages/reference/data-apis/src/type-aliases/PricesRestSchema.mdx + - page: RequestOptions + path: wallets/pages/reference/data-apis/src/type-aliases/RequestOptions.mdx + - page: SearchContractMetadataParams + path: wallets/pages/reference/data-apis/src/type-aliases/SearchContractMetadataParams.mdx + - page: SearchContractMetadataResult + path: wallets/pages/reference/data-apis/src/type-aliases/SearchContractMetadataResult.mdx + - page: SummarizeNftAttributesParams + path: wallets/pages/reference/data-apis/src/type-aliases/SummarizeNftAttributesParams.mdx + - page: SummarizeNftAttributesResult + path: wallets/pages/reference/data-apis/src/type-aliases/SummarizeNftAttributesResult.mdx + - section: Variables + contents: + - page: VERSION + path: wallets/pages/reference/data-apis/src/variables/VERSION.mdx - section: AA Infra path: wallets/pages/reference/aa-infra/src/README.mdx contents: @@ -526,6 +779,10 @@ navigation: contents: - page: AccountNotFoundError path: wallets/pages/reference/common/src/classes/AccountNotFoundError.mdx + - page: AlchemyApiError + path: wallets/pages/reference/common/src/classes/AlchemyApiError.mdx + - page: AlchemyRestClient + path: wallets/pages/reference/common/src/classes/AlchemyRestClient.mdx - page: BaseError path: wallets/pages/reference/common/src/classes/BaseError.mdx - page: ChainNotFoundError @@ -550,6 +807,8 @@ navigation: path: wallets/pages/reference/common/src/functions/bigIntMax.mdx - page: bigIntMultiply path: wallets/pages/reference/common/src/functions/bigIntMultiply.mdx + - page: composeSignals + path: wallets/pages/reference/common/src/functions/composeSignals.mdx - page: getAlchemyRpcUrl path: wallets/pages/reference/common/src/functions/getAlchemyRpcUrl.mdx - page: getSupportedChainIds @@ -564,6 +823,10 @@ navigation: path: wallets/pages/reference/common/src/functions/lowerAddress.mdx - page: raise path: wallets/pages/reference/common/src/functions/raise.mdx + - page: resolveNetwork + path: wallets/pages/reference/common/src/functions/resolveNetwork.mdx + - page: sleep + path: wallets/pages/reference/common/src/functions/sleep.mdx - page: validateAlchemyConnectionConfig path: wallets/pages/reference/common/src/functions/validateAlchemyConnectionConfig.mdx - section: Interfaces @@ -572,14 +835,38 @@ navigation: path: wallets/pages/reference/common/src/interfaces/AlchemyTransportConfig.mdx - section: Type Aliases contents: + - page: AlchemyApiErrorDetails + path: wallets/pages/reference/common/src/type-aliases/AlchemyApiErrorDetails.mdx - page: AlchemyConnectionConfig path: wallets/pages/reference/common/src/type-aliases/AlchemyConnectionConfig.mdx + - page: AlchemyNetwork + path: wallets/pages/reference/common/src/type-aliases/AlchemyNetwork.mdx + - page: AlchemyRestClientParams + path: wallets/pages/reference/common/src/type-aliases/AlchemyRestClientParams.mdx - page: AlchemyTransport path: wallets/pages/reference/common/src/type-aliases/AlchemyTransport.mdx - page: ExtractRpcMethod path: wallets/pages/reference/common/src/type-aliases/ExtractRpcMethod.mdx + - page: KnownAlchemyNetwork + path: wallets/pages/reference/common/src/type-aliases/KnownAlchemyNetwork.mdx + - page: NetworkInput + path: wallets/pages/reference/common/src/type-aliases/NetworkInput.mdx - page: Never path: wallets/pages/reference/common/src/type-aliases/Never.mdx + - page: QueryParams + path: wallets/pages/reference/common/src/type-aliases/QueryParams.mdx + - page: QueryValue + path: wallets/pages/reference/common/src/type-aliases/QueryValue.mdx + - page: ResolvedNetwork + path: wallets/pages/reference/common/src/type-aliases/ResolvedNetwork.mdx + - page: RestRequestFn + path: wallets/pages/reference/common/src/type-aliases/RestRequestFn.mdx + - page: RestRequestOptions + path: wallets/pages/reference/common/src/type-aliases/RestRequestOptions.mdx + - page: RestRequestParams + path: wallets/pages/reference/common/src/type-aliases/RestRequestParams.mdx + - page: RestRequestSchema + path: wallets/pages/reference/common/src/type-aliases/RestRequestSchema.mdx - section: Variables contents: - page: AlchemyConnectionConfigSchema diff --git a/docs/pages/reference/common/src/README.mdx b/docs/pages/reference/common/src/README.mdx index 7ab81f3036..a5d7f866ed 100644 --- a/docs/pages/reference/common/src/README.mdx +++ b/docs/pages/reference/common/src/README.mdx @@ -44,16 +44,18 @@ MIT ## Classes -| Class | Description | -| :--------------------------------------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [AccountNotFoundError](/wallets/reference/common/classes/AccountNotFoundError) | This error is thrown when an account could not be found to execute a specific action. It extends the `BaseError` class. | -| [BaseError](/wallets/reference/common/classes/BaseError) | A custom error class that extends from `ViemBaseError`. This class allows for error messages to include links to relevant documentation based on provided `docsPath` and `docsSlug` parameters. This is based on on viem's BaseError type (obviously from the import and extend) we want the errors here to point to our docs if we supply a docsPath though | -| [ChainNotFoundError](/wallets/reference/common/classes/ChainNotFoundError) | Error class representing a "Chain Not Found" error, typically thrown when no chain is supplied to the client. | -| [ConnectionConfigError](/wallets/reference/common/classes/ConnectionConfigError) | Error class for connection configuration validation failures. | -| [FetchError](/wallets/reference/common/classes/FetchError) | Error class representing a "Fetch Error" error, typically thrown when a fetch request fails. | -| [InvalidRequestError](/wallets/reference/common/classes/InvalidRequestError) | This error is thrown when an invalid request is made. It extends the `BaseError` class. | -| [MethodUnsupportedError](/wallets/reference/common/classes/MethodUnsupportedError) | This error is thrown when an unknown method is called. It extends the `BaseError` class. | -| [ServerError](/wallets/reference/common/classes/ServerError) | Error class representing a "Server Error" error, typically thrown when a server request fails. | +| Class | Description | +| :--------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| [AccountNotFoundError](/wallets/reference/common/classes/AccountNotFoundError) | This error is thrown when an account could not be found to execute a specific action. It extends the `BaseError` class. | +| [AlchemyApiError](/wallets/reference/common/classes/AlchemyApiError) | The normalized error family for Alchemy API failures. Both the REST channel (AlchemyRestClient → ServerError/FetchError, which extend this class) and SDK JSON-RPC actions surface failures as AlchemyApiError, so consumers can handle status/code/requestId/retryAfter uniformly: | +| [AlchemyRestClient](/wallets/reference/common/classes/AlchemyRestClient) | A client for making requests to Alchemy's non-JSON-RPC endpoints, with typed routes/bodies/queries (via a RestRequestSchema), bounded retries with exponential backoff (429/5xx/network only, honoring Retry-After), per-attempt timeouts, abort support, and a per-request idempotency id sent as X-Alchemy-Client-Request-Id and surfaced on thrown errors. | +| [BaseError](/wallets/reference/common/classes/BaseError) | A custom error class that extends from `ViemBaseError`. This class allows for error messages to include links to relevant documentation based on provided `docsPath` and `docsSlug` parameters. This is based on on viem's BaseError type (obviously from the import and extend) we want the errors here to point to our docs if we supply a docsPath though | +| [ChainNotFoundError](/wallets/reference/common/classes/ChainNotFoundError) | Error class representing a "Chain Not Found" error, typically thrown when no chain is supplied to the client. | +| [ConnectionConfigError](/wallets/reference/common/classes/ConnectionConfigError) | Error class for connection configuration validation failures. | +| [FetchError](/wallets/reference/common/classes/FetchError) | Error class representing a "Fetch Error" error, typically thrown when a fetch request fails. | +| [InvalidRequestError](/wallets/reference/common/classes/InvalidRequestError) | This error is thrown when an invalid request is made. It extends the `BaseError` class. | +| [MethodUnsupportedError](/wallets/reference/common/classes/MethodUnsupportedError) | This error is thrown when an unknown method is called. It extends the `BaseError` class. | +| [ServerError](/wallets/reference/common/classes/ServerError) | Error class representing a "Server Error" error, typically thrown when a server request fails. | ## Interfaces @@ -63,12 +65,24 @@ MIT ## Type Aliases -| Type Alias | Description | -| :---------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------ | -| [AlchemyConnectionConfig](/wallets/reference/common/type-aliases/AlchemyConnectionConfig) | TypeScript type derived from the schema for external consumption. This provides clean type inference without exposing Zod implementation details. | -| [AlchemyTransport](/wallets/reference/common/type-aliases/AlchemyTransport) | - | -| [ExtractRpcMethod](/wallets/reference/common/type-aliases/ExtractRpcMethod) | - | -| [Never](/wallets/reference/common/type-aliases/Never) | - | +| Type Alias | Description | +| :---------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [AlchemyApiErrorDetails](/wallets/reference/common/type-aliases/AlchemyApiErrorDetails) | Normalized failure metadata shared across REST and JSON-RPC channels. | +| [AlchemyConnectionConfig](/wallets/reference/common/type-aliases/AlchemyConnectionConfig) | TypeScript type derived from the schema for external consumption. This provides clean type inference without exposing Zod implementation details. | +| [AlchemyNetwork](/wallets/reference/common/type-aliases/AlchemyNetwork) | An Alchemy network identifier. Known slugs get autocomplete; arbitrary strings are accepted as an escape hatch so new networks work without an SDK release. | +| [AlchemyRestClientParams](/wallets/reference/common/type-aliases/AlchemyRestClientParams) | Parameters for creating an AlchemyRestClient instance. | +| [AlchemyTransport](/wallets/reference/common/type-aliases/AlchemyTransport) | - | +| [ExtractRpcMethod](/wallets/reference/common/type-aliases/ExtractRpcMethod) | - | +| [KnownAlchemyNetwork](/wallets/reference/common/type-aliases/KnownAlchemyNetwork) | Known Alchemy network slugs for autocomplete. | +| [NetworkInput](/wallets/reference/common/type-aliases/NetworkInput) | Any accepted network input: a viem Chain, an Alchemy network slug (e.g. "eth-mainnet"), or a CAIP-2 identifier (e.g. "eip155:1", "solana:mainnet"). | +| [Never](/wallets/reference/common/type-aliases/Never) | - | +| [QueryParams](/wallets/reference/common/type-aliases/QueryParams) | A query-params object; array values serialize as repeated keys. | +| [QueryValue](/wallets/reference/common/type-aliases/QueryValue) | Values the query serializer accepts (null/undefined entries are skipped). | +| [ResolvedNetwork](/wallets/reference/common/type-aliases/ResolvedNetwork) | A resolved network: the Alchemy slug used for URL construction and REST payloads, plus the numeric chain ID when one exists (EVM only). | +| [RestRequestFn](/wallets/reference/common/type-aliases/RestRequestFn) | - | +| [RestRequestOptions](/wallets/reference/common/type-aliases/RestRequestOptions) | Per-request runtime options; values override the client-level defaults. | +| [RestRequestParams](/wallets/reference/common/type-aliases/RestRequestParams) | - | +| [RestRequestSchema](/wallets/reference/common/type-aliases/RestRequestSchema) | - | ## Variables @@ -78,17 +92,20 @@ MIT ## Functions -| Function | Description | -| :----------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [alchemyTransport](/wallets/reference/common/functions/alchemyTransport) | Creates an Alchemy HTTP transport for connecting to Alchemy's services. | -| [assertNever](/wallets/reference/common/functions/assertNever) | Asserts that a value is never. | -| [bigIntMax](/wallets/reference/common/functions/bigIntMax) | Returns the max bigint in a list of bigints | -| [bigIntMultiply](/wallets/reference/common/functions/bigIntMultiply) | Given a bigint and a number (which can be a float), returns the bigint value. Note: this function has loss and will round down to the nearest integer. | -| [getAlchemyRpcUrl](/wallets/reference/common/functions/getAlchemyRpcUrl) | Gets the Alchemy RPC base URL for a given chain ID. | -| [getSupportedChainIds](/wallets/reference/common/functions/getSupportedChainIds) | Gets all supported chain IDs from the registry. | -| [isAlchemyConnectionConfig](/wallets/reference/common/functions/isAlchemyConnectionConfig) | Type guard to check if a value is a valid Alchemy connection config. | -| [isAlchemyTransport](/wallets/reference/common/functions/isAlchemyTransport) | A type guard for the transport to determine if it is an Alchemy transport. Used in cases where we would like to do switching depending on the transport. | -| [isChainSupported](/wallets/reference/common/functions/isChainSupported) | Checks if a chain ID is supported by the Alchemy RPC registry. | -| [lowerAddress](/wallets/reference/common/functions/lowerAddress) | Lowercase an address | -| [raise](/wallets/reference/common/functions/raise) | Raises an error. | -| [validateAlchemyConnectionConfig](/wallets/reference/common/functions/validateAlchemyConnectionConfig) | Validates an Alchemy connection configuration object. | +| Function | Description | +| :----------------------------------------------------------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [alchemyTransport](/wallets/reference/common/functions/alchemyTransport) | Creates an Alchemy HTTP transport for connecting to Alchemy's services. | +| [assertNever](/wallets/reference/common/functions/assertNever) | Asserts that a value is never. | +| [bigIntMax](/wallets/reference/common/functions/bigIntMax) | Returns the max bigint in a list of bigints | +| [bigIntMultiply](/wallets/reference/common/functions/bigIntMultiply) | Given a bigint and a number (which can be a float), returns the bigint value. Note: this function has loss and will round down to the nearest integer. | +| [composeSignals](/wallets/reference/common/functions/composeSignals) | Combines multiple abort signals into one that aborts when any input aborts. Uses AbortSignal.any where available, with an addEventListener fallback. | +| [getAlchemyRpcUrl](/wallets/reference/common/functions/getAlchemyRpcUrl) | Gets the Alchemy RPC base URL for a given chain ID. | +| [getSupportedChainIds](/wallets/reference/common/functions/getSupportedChainIds) | Gets all supported chain IDs from the registry. | +| [isAlchemyConnectionConfig](/wallets/reference/common/functions/isAlchemyConnectionConfig) | Type guard to check if a value is a valid Alchemy connection config. | +| [isAlchemyTransport](/wallets/reference/common/functions/isAlchemyTransport) | A type guard for the transport to determine if it is an Alchemy transport. Used in cases where we would like to do switching depending on the transport. | +| [isChainSupported](/wallets/reference/common/functions/isChainSupported) | Checks if a chain ID is supported by the Alchemy RPC registry. | +| [lowerAddress](/wallets/reference/common/functions/lowerAddress) | Lowercase an address | +| [raise](/wallets/reference/common/functions/raise) | Raises an error. | +| [resolveNetwork](/wallets/reference/common/functions/resolveNetwork) | Resolves any accepted network input — viem Chain, Alchemy network slug, or CAIP-2 identifier — to the Alchemy network slug (and chain ID when one exists). All three forms resolve against the same daikon-generated registry. | +| [sleep](/wallets/reference/common/functions/sleep) | Waits for a duration, rejecting immediately with the signal's reason if the signal aborts first. | +| [validateAlchemyConnectionConfig](/wallets/reference/common/functions/validateAlchemyConnectionConfig) | Validates an Alchemy connection configuration object. | diff --git a/docs/pages/reference/common/src/classes/AlchemyApiError.mdx b/docs/pages/reference/common/src/classes/AlchemyApiError.mdx new file mode 100644 index 0000000000..74272e42c8 --- /dev/null +++ b/docs/pages/reference/common/src/classes/AlchemyApiError.mdx @@ -0,0 +1,219 @@ +--- +title: AlchemyApiError +description: "The normalized error family for Alchemy API failures. Both the REST channel (AlchemyRestClient → ServerError/FetchError, which extend this class) and SDK JSON-RPC actions surface failures as AlchemyApiError, so consumers can handle status/code/requestId/retryAfter uniformly: ```ts try { ... } catch (e) { if (e instanceof AlchemyApiError && e.status === 429) { await sleep(e.retryAfter ?? 1_000); } } ```" +slug: wallets/reference/common/classes/AlchemyApiError +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +Defined in: [packages/common/src/errors/AlchemyApiError.ts:29](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/common/src/errors/AlchemyApiError.ts#L29) + +The normalized error family for Alchemy API failures. Both the REST channel +(AlchemyRestClient → ServerError/FetchError, which extend this class) and +SDK JSON-RPC actions surface failures as AlchemyApiError, so consumers can +handle status/code/requestId/retryAfter uniformly: + +```ts +try { ... } catch (e) { + if (e instanceof AlchemyApiError && e.status === 429) { + await sleep(e.retryAfter ?? 1_000); + } +} +``` + +## Extends + +- [`BaseError`](BaseError) + +## Extended by + +- [`FetchError`](FetchError) +- [`ServerError`](ServerError) + +## Constructors + +### Constructor + +```ts +new AlchemyApiError(shortMessage, args?): AlchemyApiError; +``` + +Defined in: [packages/common/src/errors/AlchemyApiError.ts:47](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/common/src/errors/AlchemyApiError.ts#L47) + +Creates a normalized API error. + +#### Parameters + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
+ `shortMessage` + + `string` + + The headline error message +
+ `args?` + + [`AlchemyApiErrorDetails`](../type-aliases/AlchemyApiErrorDetails) & `object` + + Failure metadata plus BaseError options +
+ +#### Returns + +`AlchemyApiError` + +#### Overrides + +[`BaseError`](BaseError).[`constructor`](BaseError#constructor) + +## Properties + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PropertyTypeDefault valueDescription
+ `code?` + + `string` | `number` + + `undefined` + + Provider error code: JSON-RPC `error.code` or a REST error-body code. +
+ `name` + + `string` + + `"AlchemyApiError"` + + ‐ +
+ `requestId?` + + `string` + + `undefined` + + The client-generated X-Alchemy-Client-Request-Id sent with the request. +
+ `retryAfter?` + + `number` + + `undefined` + + Parsed Retry-After hint in milliseconds, when the server provided one. +
+ `status?` + + `number` + + `undefined` + + HTTP status code, when the failure was an HTTP response. +
+ `version` + + `string` + + `VERSION` + + ‐ +
diff --git a/docs/pages/reference/common/src/classes/AlchemyRestClient.mdx b/docs/pages/reference/common/src/classes/AlchemyRestClient.mdx new file mode 100644 index 0000000000..f6c7b4a980 --- /dev/null +++ b/docs/pages/reference/common/src/classes/AlchemyRestClient.mdx @@ -0,0 +1,115 @@ +--- +title: AlchemyRestClient +description: A client for making requests to Alchemy's non-JSON-RPC endpoints, with typed routes/bodies/queries (via a RestRequestSchema), bounded retries with exponential backoff (429/5xx/network only, honoring Retry-After), per-attempt timeouts, abort support, and a per-request idempotency id sent as X-Alchemy-Client-Request-Id and surfaced on thrown errors. +slug: wallets/reference/common/classes/AlchemyRestClient +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +Defined in: [packages/common/src/rest/restClient.ts:101](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/common/src/rest/restClient.ts#L101) + +A client for making requests to Alchemy's non-JSON-RPC endpoints, with +typed routes/bodies/queries (via a RestRequestSchema), bounded retries with +exponential backoff (429/5xx/network only, honoring Retry-After), +per-attempt timeouts, abort support, and a per-request idempotency id sent +as X-Alchemy-Client-Request-Id and surfaced on thrown errors. + +## Type Parameters + + + + + + + + + + + + + +
Type Parameter
+ `Schema` *extends* [`RestRequestSchema`](../type-aliases/RestRequestSchema) +
+ +## Constructors + +### Constructor + +```ts +new AlchemyRestClient(params): AlchemyRestClient; +``` + +Defined in: [packages/common/src/rest/restClient.ts:113](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/common/src/rest/restClient.ts#L113) + +Creates a new instance of AlchemyRestClient. + +#### Parameters + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
+ `params` + + [`AlchemyRestClientParams`](../type-aliases/AlchemyRestClientParams) + + The parameters for configuring the client, including API key, JWT, custom URL, headers, and retry/timeout defaults. +
+ +#### Returns + +`AlchemyRestClient`\<`Schema`> + +## Properties + + + + + + + + + + + + + + + + + + + + +
PropertyTypeDescription
+ `request` + + [`RestRequestFn`](../type-aliases/RestRequestFn)\<`Schema`> + + Makes an HTTP request to an Alchemy non-JSON-RPC endpoint. Retries + 429/5xx/network failures with exponential backoff (honoring Retry-After); + other statuses throw immediately. A caller-initiated abort is never + retried. + + **Param** + + The parameters for the request +
diff --git a/docs/pages/reference/common/src/classes/BaseError.mdx b/docs/pages/reference/common/src/classes/BaseError.mdx index 41d41c8939..3b4dc5e5ce 100644 --- a/docs/pages/reference/common/src/classes/BaseError.mdx +++ b/docs/pages/reference/common/src/classes/BaseError.mdx @@ -19,11 +19,10 @@ we want the errors here to point to our docs if we supply a docsPath though ## Extended by +- [`AlchemyApiError`](AlchemyApiError) - [`ChainNotFoundError`](ChainNotFoundError) - [`AccountNotFoundError`](AccountNotFoundError) - [`ConnectionConfigError`](ConnectionConfigError) -- [`FetchError`](FetchError) -- [`ServerError`](ServerError) - [`InvalidRequestError`](InvalidRequestError) - [`MethodUnsupportedError`](MethodUnsupportedError) diff --git a/docs/pages/reference/common/src/classes/FetchError.mdx b/docs/pages/reference/common/src/classes/FetchError.mdx index aaa76be35b..6cf6e9b1da 100644 --- a/docs/pages/reference/common/src/classes/FetchError.mdx +++ b/docs/pages/reference/common/src/classes/FetchError.mdx @@ -7,13 +7,13 @@ layout: reference {/* This file is auto-generated by TypeDoc. Do not edit manually. */} -Defined in: [packages/common/src/errors/FetchError.ts:6](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/common/src/errors/FetchError.ts#L6) +Defined in: [packages/common/src/errors/FetchError.ts:9](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/common/src/errors/FetchError.ts#L9) Error class representing a "Fetch Error" error, typically thrown when a fetch request fails. ## Extends -- [`BaseError`](BaseError) +- [`AlchemyApiError`](AlchemyApiError) ## Constructors @@ -23,12 +23,13 @@ Error class representing a "Fetch Error" error, typically thrown when a fetch re new FetchError( route, method, - cause?): FetchError; + cause?, + apiDetails?): FetchError; ``` -Defined in: [packages/common/src/errors/FetchError.ts:16](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/common/src/errors/FetchError.ts#L16) +Defined in: [packages/common/src/errors/FetchError.ts:20](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/common/src/errors/FetchError.ts#L20) -Initializes a new instance of the error message with a default message indicating that no chain was supplied to the client. +Initializes a new fetch error for a request that failed before a response. #### Parameters @@ -84,6 +85,20 @@ Initializes a new instance of the error message with a default message indicatin + + + `apiDetails?` + + + + [`AlchemyApiErrorDetails`](../type-aliases/AlchemyApiErrorDetails) + + + + Normalized failure metadata (requestId). + + + @@ -93,7 +108,7 @@ Initializes a new instance of the error message with a default message indicatin #### Overrides -[`BaseError`](BaseError).[`constructor`](BaseError#constructor) +[`AlchemyApiError`](AlchemyApiError).[`constructor`](AlchemyApiError#constructor) ## Properties @@ -103,10 +118,29 @@ Initializes a new instance of the error message with a default message indicatin Property Type Default value + Description + + + `code?` + + + + `string` | `number` + + + + `undefined` + + + + Provider error code: JSON-RPC `error.code` or a REST error-body code. + + + `name` @@ -119,6 +153,64 @@ Initializes a new instance of the error message with a default message indicatin `"FetchError"` + + + ‐ + + + + + + `requestId?` + + + + `string` + + + + `undefined` + + + + The client-generated X-Alchemy-Client-Request-Id sent with the request. + + + + + + `retryAfter?` + + + + `number` + + + + `undefined` + + + + Parsed Retry-After hint in milliseconds, when the server provided one. + + + + + + `status?` + + + + `number` + + + + `undefined` + + + + HTTP status code, when the failure was an HTTP response. + @@ -133,6 +225,10 @@ Initializes a new instance of the error message with a default message indicatin `VERSION` + + + ‐ + diff --git a/docs/pages/reference/common/src/classes/ServerError.mdx b/docs/pages/reference/common/src/classes/ServerError.mdx index a326a3378d..ae246e9c6e 100644 --- a/docs/pages/reference/common/src/classes/ServerError.mdx +++ b/docs/pages/reference/common/src/classes/ServerError.mdx @@ -7,13 +7,13 @@ layout: reference {/* This file is auto-generated by TypeDoc. Do not edit manually. */} -Defined in: [packages/common/src/errors/ServerError.ts:6](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/common/src/errors/ServerError.ts#L6) +Defined in: [packages/common/src/errors/ServerError.ts:9](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/common/src/errors/ServerError.ts#L9) Error class representing a "Server Error" error, typically thrown when a server request fails. ## Extends -- [`BaseError`](BaseError) +- [`AlchemyApiError`](AlchemyApiError) ## Constructors @@ -23,12 +23,13 @@ Error class representing a "Server Error" error, typically thrown when a server new ServerError( message, status, - cause?): ServerError; + cause?, + apiDetails?): ServerError; ``` -Defined in: [packages/common/src/errors/ServerError.ts:16](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/common/src/errors/ServerError.ts#L16) +Defined in: [packages/common/src/errors/ServerError.ts:20](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/common/src/errors/ServerError.ts#L20) -Initializes a new instance of the error message with a default message indicating that no chain was supplied to the client. +Initializes a new server error for a failed HTTP response. #### Parameters @@ -84,6 +85,20 @@ Initializes a new instance of the error message with a default message indicatin + + + `apiDetails?` + + + + [`AlchemyApiErrorDetails`](../type-aliases/AlchemyApiErrorDetails) + + + + Normalized failure metadata (requestId, retryAfter, code). + + + @@ -93,7 +108,7 @@ Initializes a new instance of the error message with a default message indicatin #### Overrides -[`BaseError`](BaseError).[`constructor`](BaseError#constructor) +[`AlchemyApiError`](AlchemyApiError).[`constructor`](AlchemyApiError#constructor) ## Properties @@ -103,10 +118,29 @@ Initializes a new instance of the error message with a default message indicatin Property Type Default value + Description + + + `code?` + + + + `string` | `number` + + + + `undefined` + + + + Provider error code: JSON-RPC `error.code` or a REST error-body code. + + + `name` @@ -119,6 +153,64 @@ Initializes a new instance of the error message with a default message indicatin `"ServerError"` + + + ‐ + + + + + + `requestId?` + + + + `string` + + + + `undefined` + + + + The client-generated X-Alchemy-Client-Request-Id sent with the request. + + + + + + `retryAfter?` + + + + `number` + + + + `undefined` + + + + Parsed Retry-After hint in milliseconds, when the server provided one. + + + + + + `status?` + + + + `number` + + + + `undefined` + + + + HTTP status code, when the failure was an HTTP response. + @@ -133,6 +225,10 @@ Initializes a new instance of the error message with a default message indicatin `VERSION` + + + ‐ + diff --git a/docs/pages/reference/common/src/functions/composeSignals.mdx b/docs/pages/reference/common/src/functions/composeSignals.mdx new file mode 100644 index 0000000000..e148bcc037 --- /dev/null +++ b/docs/pages/reference/common/src/functions/composeSignals.mdx @@ -0,0 +1,52 @@ +--- +title: composeSignals +description: Overview of the composeSignals function +slug: wallets/reference/common/functions/composeSignals +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +function composeSignals(...signals): undefined | AbortSignal; +``` + +Defined in: [packages/common/src/utils/signals.ts:8](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/common/src/utils/signals.ts#L8) + +Combines multiple abort signals into one that aborts when any input aborts. +Uses AbortSignal.any where available, with an addEventListener fallback. + +## Parameters + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
+ ...`signals` + + (`undefined` | `AbortSignal`)\[] + + Signals to combine (undefined entries are skipped) +
+ +## Returns + +`undefined` | `AbortSignal` + +The combined signal, or undefined if none were provided diff --git a/docs/pages/reference/common/src/functions/resolveNetwork.mdx b/docs/pages/reference/common/src/functions/resolveNetwork.mdx new file mode 100644 index 0000000000..c5d2694abf --- /dev/null +++ b/docs/pages/reference/common/src/functions/resolveNetwork.mdx @@ -0,0 +1,63 @@ +--- +title: resolveNetwork +description: Overview of the resolveNetwork function +slug: wallets/reference/common/functions/resolveNetwork +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +function resolveNetwork(input): ResolvedNetwork; +``` + +Defined in: [packages/common/src/networks/networkRegistry.ts:93](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/common/src/networks/networkRegistry.ts#L93) + +Resolves any accepted network input — viem Chain, Alchemy network slug, or +CAIP-2 identifier — to the Alchemy network slug (and chain ID when one +exists). All three forms resolve against the same daikon-generated registry. + +## Example + +```ts +import { mainnet } from "viem/chains"; +resolveNetwork(mainnet); // { slug: "eth-mainnet", chainId: 1 } +resolveNetwork("eth-mainnet"); // { slug: "eth-mainnet", chainId: 1 } +resolveNetwork("eip155:1"); // { slug: "eth-mainnet", chainId: 1 } +resolveNetwork("solana:mainnet"); // { slug: "solana-mainnet" } +``` + +## Parameters + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
+ `input` + + [`NetworkInput`](../type-aliases/NetworkInput) + + The network to resolve +
+ +## Returns + +[`ResolvedNetwork`](../type-aliases/ResolvedNetwork) + +The resolved slug and optional chain ID diff --git a/docs/pages/reference/common/src/functions/sleep.mdx b/docs/pages/reference/common/src/functions/sleep.mdx new file mode 100644 index 0000000000..155871898f --- /dev/null +++ b/docs/pages/reference/common/src/functions/sleep.mdx @@ -0,0 +1,66 @@ +--- +title: sleep +description: Overview of the sleep function +slug: wallets/reference/common/functions/sleep +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +function sleep(ms, signal?): Promise; +``` + +Defined in: [packages/common/src/utils/signals.ts:39](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/common/src/utils/signals.ts#L39) + +Waits for a duration, rejecting immediately with the signal's reason if the +signal aborts first. + +## Parameters + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
+ `ms` + + `number` + + Milliseconds to wait +
+ `signal?` + + `AbortSignal` + + Optional abort signal +
+ +## Returns + +`Promise`\<`void`> + +Resolves after the delay diff --git a/docs/pages/reference/common/src/type-aliases/AlchemyApiErrorDetails.mdx b/docs/pages/reference/common/src/type-aliases/AlchemyApiErrorDetails.mdx new file mode 100644 index 0000000000..8a25e5927c --- /dev/null +++ b/docs/pages/reference/common/src/type-aliases/AlchemyApiErrorDetails.mdx @@ -0,0 +1,87 @@ +--- +title: AlchemyApiErrorDetails +description: Normalized failure metadata shared across REST and JSON-RPC channels. +slug: wallets/reference/common/type-aliases/AlchemyApiErrorDetails +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type AlchemyApiErrorDetails = object; +``` + +Defined in: [packages/common/src/errors/AlchemyApiError.ts:4](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/common/src/errors/AlchemyApiError.ts#L4) + +Normalized failure metadata shared across REST and JSON-RPC channels. + +## Properties + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PropertyTypeDescription
+ `code?` + + `number` | `string` + + Provider error code: JSON-RPC `error.code` or a REST error-body code. +
+ `requestId?` + + `string` + + The client-generated X-Alchemy-Client-Request-Id sent with the request. +
+ `retryAfter?` + + `number` + + Parsed Retry-After hint in milliseconds, when the server provided one. +
+ `status?` + + `number` + + HTTP status code, when the failure was an HTTP response. +
diff --git a/docs/pages/reference/common/src/type-aliases/AlchemyNetwork.mdx b/docs/pages/reference/common/src/type-aliases/AlchemyNetwork.mdx new file mode 100644 index 0000000000..78145390ee --- /dev/null +++ b/docs/pages/reference/common/src/type-aliases/AlchemyNetwork.mdx @@ -0,0 +1,18 @@ +--- +title: AlchemyNetwork +description: An Alchemy network identifier. Known slugs get autocomplete; arbitrary strings are accepted as an escape hatch so new networks work without an SDK release. +slug: wallets/reference/common/type-aliases/AlchemyNetwork +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type AlchemyNetwork = KnownAlchemyNetwork | (string & object); +``` + +Defined in: [packages/common/src/networks/networkRegistry.ts:31](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/common/src/networks/networkRegistry.ts#L31) + +An Alchemy network identifier. Known slugs get autocomplete; arbitrary +strings are accepted as an escape hatch so new networks work without an +SDK release. diff --git a/docs/pages/reference/common/src/type-aliases/AlchemyRestClientParams.mdx b/docs/pages/reference/common/src/type-aliases/AlchemyRestClientParams.mdx new file mode 100644 index 0000000000..f9368f5e45 --- /dev/null +++ b/docs/pages/reference/common/src/type-aliases/AlchemyRestClientParams.mdx @@ -0,0 +1,129 @@ +--- +title: AlchemyRestClientParams +description: Parameters for creating an AlchemyRestClient instance. +slug: wallets/reference/common/type-aliases/AlchemyRestClientParams +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type AlchemyRestClientParams = object; +``` + +Defined in: [packages/common/src/rest/restClient.ts:16](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/common/src/rest/restClient.ts#L16) + +Parameters for creating an AlchemyRestClient instance. + +## Properties + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PropertyTypeDescription
+ `apiKey?` + + `string` + + API key for Alchemy authentication +
+ `headers?` + + `HeadersInit` + + Custom headers to be sent with requests +
+ `jwt?` + + `string` + + JWT token for Alchemy authentication +
+ `retryCount?` + + `number` + + Max retry attempts after the initial request (default 3; retries 429/5xx/network only) +
+ `retryDelay?` + + `number` + + Base backoff delay in ms, doubled per attempt (default 150) +
+ `timeout?` + + `number` + + Per-attempt timeout in ms (default 10000) +
+ `url?` + + `string` + + Custom URL (optional - defaults to Alchemy's chain-agnostic URL, but can be used to override it) +
diff --git a/docs/pages/reference/common/src/type-aliases/KnownAlchemyNetwork.mdx b/docs/pages/reference/common/src/type-aliases/KnownAlchemyNetwork.mdx new file mode 100644 index 0000000000..0cf69c5d59 --- /dev/null +++ b/docs/pages/reference/common/src/type-aliases/KnownAlchemyNetwork.mdx @@ -0,0 +1,32 @@ +--- +title: KnownAlchemyNetwork +description: "Known Alchemy network slugs for autocomplete. TODO(data-sdk): generate this union from daikon via the ws-tools CLI in the same pass that generates ALCHEMY_RPC_MAPPING, so it is never hand-maintained. This subset exists to prove the MVP only." +slug: wallets/reference/common/type-aliases/KnownAlchemyNetwork +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type KnownAlchemyNetwork = + | "eth-mainnet" + | "eth-sepolia" + | "base-mainnet" + | "base-sepolia" + | "polygon-mainnet" + | "polygon-amoy" + | "arb-mainnet" + | "arb-sepolia" + | "opt-mainnet" + | "opt-sepolia" + | "solana-mainnet" + | "solana-devnet"; +``` + +Defined in: [packages/common/src/networks/networkRegistry.ts:12](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/common/src/networks/networkRegistry.ts#L12) + +Known Alchemy network slugs for autocomplete. + +TODO(data-sdk): generate this union from daikon via the ws-tools CLI in the +same pass that generates ALCHEMY_RPC_MAPPING, so it is never hand-maintained. +This subset exists to prove the MVP only. diff --git a/docs/pages/reference/common/src/type-aliases/NetworkInput.mdx b/docs/pages/reference/common/src/type-aliases/NetworkInput.mdx new file mode 100644 index 0000000000..e2c2cd6f13 --- /dev/null +++ b/docs/pages/reference/common/src/type-aliases/NetworkInput.mdx @@ -0,0 +1,18 @@ +--- +title: NetworkInput +description: 'Any accepted network input: a viem Chain, an Alchemy network slug (e.g. "eth-mainnet"), or a CAIP-2 identifier (e.g. "eip155:1", "solana:mainnet").' +slug: wallets/reference/common/type-aliases/NetworkInput +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type NetworkInput = Chain | AlchemyNetwork; +``` + +Defined in: [packages/common/src/networks/networkRegistry.ts:38](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/common/src/networks/networkRegistry.ts#L38) + +Any accepted network input: a viem Chain, an Alchemy network slug +(e.g. "eth-mainnet"), or a CAIP-2 identifier (e.g. "eip155:1", +"solana:mainnet"). diff --git a/docs/pages/reference/common/src/type-aliases/QueryParams.mdx b/docs/pages/reference/common/src/type-aliases/QueryParams.mdx new file mode 100644 index 0000000000..1fbe615516 --- /dev/null +++ b/docs/pages/reference/common/src/type-aliases/QueryParams.mdx @@ -0,0 +1,16 @@ +--- +title: QueryParams +description: A query-params object; array values serialize as repeated keys. +slug: wallets/reference/common/type-aliases/QueryParams +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type QueryParams = Record; +``` + +Defined in: [packages/common/src/rest/types.ts:7](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/common/src/rest/types.ts#L7) + +A query-params object; array values serialize as repeated keys. diff --git a/docs/pages/reference/common/src/type-aliases/QueryValue.mdx b/docs/pages/reference/common/src/type-aliases/QueryValue.mdx new file mode 100644 index 0000000000..f4a7b99373 --- /dev/null +++ b/docs/pages/reference/common/src/type-aliases/QueryValue.mdx @@ -0,0 +1,16 @@ +--- +title: QueryValue +description: Values the query serializer accepts (null/undefined entries are skipped). +slug: wallets/reference/common/type-aliases/QueryValue +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type QueryValue = string | number | boolean | null | undefined; +``` + +Defined in: [packages/common/src/rest/types.ts:4](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/common/src/rest/types.ts#L4) + +Values the query serializer accepts (null/undefined entries are skipped). diff --git a/docs/pages/reference/common/src/type-aliases/ResolvedNetwork.mdx b/docs/pages/reference/common/src/type-aliases/ResolvedNetwork.mdx new file mode 100644 index 0000000000..bcb18e80fa --- /dev/null +++ b/docs/pages/reference/common/src/type-aliases/ResolvedNetwork.mdx @@ -0,0 +1,51 @@ +--- +title: ResolvedNetwork +description: "A resolved network: the Alchemy slug used for URL construction and REST payloads, plus the numeric chain ID when one exists (EVM only)." +slug: wallets/reference/common/type-aliases/ResolvedNetwork +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type ResolvedNetwork = object; +``` + +Defined in: [packages/common/src/networks/networkRegistry.ts:44](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/common/src/networks/networkRegistry.ts#L44) + +A resolved network: the Alchemy slug used for URL construction and REST +payloads, plus the numeric chain ID when one exists (EVM only). + +## Properties + + + + + + + + + + + + + + + + + + + + + + + +
PropertyType
+ `chainId?` + + `number` +
+ `slug` + + `string` +
diff --git a/docs/pages/reference/common/src/type-aliases/RestRequestFn.mdx b/docs/pages/reference/common/src/type-aliases/RestRequestFn.mdx new file mode 100644 index 0000000000..628b472429 --- /dev/null +++ b/docs/pages/reference/common/src/type-aliases/RestRequestFn.mdx @@ -0,0 +1,104 @@ +--- +title: RestRequestFn +description: Overview of RestRequestFn +slug: wallets/reference/common/type-aliases/RestRequestFn +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type RestRequestFn = <_parameters, _returnType>( + params, +) => Promise<_returnType>; +``` + +Defined in: [packages/common/src/rest/types.ts:69](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/common/src/rest/types.ts#L69) + +## Type Parameters + + + + + + + + + + + + + + + + + +
Type ParameterDefault type
+ `Schema` *extends* [`RestRequestSchema`](RestRequestSchema) | `undefined` + + `undefined` +
+ +## Type Parameters + + + + + + + + + + + + + + + + + + + + + + + +
Type ParameterDefault type
+ `_parameters` *extends* [`RestRequestParams`](RestRequestParams)\<`Schema`> + + [`RestRequestParams`](RestRequestParams)\<`Schema`> +
+ `_returnType` + + `Schema` *extends* [`RestRequestSchema`](RestRequestSchema) ? `Extract`\<`Schema`\[`number`], \{ + `Route`: `_parameters`\[`"route"`]; + }>\[`"Response"`] : `unknown` +
+ +## Parameters + + + + + + + + + + + + + + + + + +
ParameterType
+ `params` + + `_parameters` +
+ +## Returns + +`Promise`\<`_returnType`> diff --git a/docs/pages/reference/common/src/type-aliases/RestRequestOptions.mdx b/docs/pages/reference/common/src/type-aliases/RestRequestOptions.mdx new file mode 100644 index 0000000000..9684d008a5 --- /dev/null +++ b/docs/pages/reference/common/src/type-aliases/RestRequestOptions.mdx @@ -0,0 +1,87 @@ +--- +title: RestRequestOptions +description: Per-request runtime options; values override the client-level defaults. +slug: wallets/reference/common/type-aliases/RestRequestOptions +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type RestRequestOptions = object; +``` + +Defined in: [packages/common/src/rest/types.ts:18](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/common/src/rest/types.ts#L18) + +Per-request runtime options; values override the client-level defaults. + +## Properties + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PropertyTypeDescription
+ `retryCount?` + + `number` + + Max retry attempts after the initial request (client default applies when omitted). +
+ `retryDelay?` + + `number` + + Base backoff delay in ms (client default applies when omitted). +
+ `signal?` + + `AbortSignal` + + Abort the request (and any pending retries). +
+ `timeout?` + + `number` + + Per-attempt timeout in ms (client default applies when omitted). +
diff --git a/docs/pages/reference/common/src/type-aliases/RestRequestParams.mdx b/docs/pages/reference/common/src/type-aliases/RestRequestParams.mdx new file mode 100644 index 0000000000..dd0ae54a18 --- /dev/null +++ b/docs/pages/reference/common/src/type-aliases/RestRequestParams.mdx @@ -0,0 +1,38 @@ +--- +title: RestRequestParams +description: Overview of RestRequestParams +slug: wallets/reference/common/type-aliases/RestRequestParams +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type RestRequestParams = Schema extends RestRequestSchema ? { [K in keyof Schema]: Prettify<{ method: Schema[K] extends Schema[number] ? Schema[K]["Method"] : never; route: Schema[K] extends Schema[number] ? Schema[K]["Route"] : never } & (Schema[K] extends Schema[number] ? Schema[K]["Body"] extends undefined ? { body?: undefined } : { body: (...)[(...)]["Body"] } : never) & (Schema[K] extends Schema[number] ? EntryQuery extends undefined ? { query?: undefined } : undefined extends EntryQuery<(...)[(...)]> ? { query?: EntryQuery<(...)> } : { query: EntryQuery<(...)> } : never) & RestRequestOptions> }[number] : object & RestRequestOptions; +``` + +Defined in: [packages/common/src/rest/types.ts:37](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/common/src/rest/types.ts#L37) + +## Type Parameters + + + + + + + + + + + + + + + + + +
Type ParameterDefault type
+ `Schema` *extends* [`RestRequestSchema`](RestRequestSchema) | `undefined` + + `undefined` +
diff --git a/docs/pages/reference/common/src/type-aliases/RestRequestSchema.mdx b/docs/pages/reference/common/src/type-aliases/RestRequestSchema.mdx new file mode 100644 index 0000000000..a536fa02f6 --- /dev/null +++ b/docs/pages/reference/common/src/type-aliases/RestRequestSchema.mdx @@ -0,0 +1,14 @@ +--- +title: RestRequestSchema +description: Overview of RestRequestSchema +slug: wallets/reference/common/type-aliases/RestRequestSchema +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type RestRequestSchema = readonly object[]; +``` + +Defined in: [packages/common/src/rest/types.ts:9](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/common/src/rest/types.ts#L9) diff --git a/docs/pages/reference/data-apis/src/README.mdx b/docs/pages/reference/data-apis/src/README.mdx new file mode 100644 index 0000000000..ce454ee350 --- /dev/null +++ b/docs/pages/reference/data-apis/src/README.mdx @@ -0,0 +1,204 @@ +--- +title: "@alchemy/data-apis" +description: Overview of data-apis +slug: wallets/reference/data-apis +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +A vertical-slice prototype of the Data APIs SDK, built to prove the architecture +before scaling to the full v1 surface (Portfolio, Prices, NFT, Token, Transfers). + +## What this proves + +One method per seam, not full coverage: + +| Method | Channel | What it demonstrates | +| ------------------------------ | ----------------------------------------- | -------------------------------------------------------------------------------------------------------------- | +| `portfolio.getTokensByAddress` | REST → global `api.g.alchemy.com/data/v1` | Multi-network request bodies via `AlchemyRestClient`; networks are payload, the client's chain is not involved | +| `nft.getNftsForOwner` | REST → `{network}.g.alchemy.com/nft/v3` | Network-scoped endpoint resolution with per-request `network` override falling back to the client default | +| `transfers.getAssetTransfers` | JSON-RPC → `AlchemyTransport` | Plain viem action; network override derives a transport instance from `client.transport.config` | + +Plus the two entry points: + +```ts +// Data-only developers (no viem knowledge required) +const data = createDataClient({ apiKey, network: "eth-mainnet" }); + +// Developers already on a viem client with an Alchemy transport +const client = createClient({ + chain: mainnet, + transport: alchemyTransport({ apiKey }), +}).extend(dataActions); +``` + +Network inputs accept all three formats everywhere, resolved by +`resolveNetwork()` in `@alchemy/common`: a viem `Chain`, an Alchemy slug +(`"eth-mainnet"`), or CAIP-2 (`"eip155:1"`, `"solana:mainnet"`). The slug ↔ +chain-ID mapping is derived from the existing daikon-generated +`ALCHEMY_RPC_MAPPING` — no second registry. + +## Generated internals + +Param/result types are generated from the docs repo's bundled OpenAPI/OpenRPC +specs by `@alchemy/api-codegen` (see that package's README for the +snapshot/generate pipeline). `src/generated/` is committed, machine-owned, and +never re-exported directly: the public types in `src/types.ts` are +hand-reviewed aliases, and `codegen.manifest.ts` maps spec operations to the +generated surface — referencing a renamed/removed spec operation fails +`pnpm generate` loudly. + +## Companion changes in @alchemy/common + +- `networks/networkRegistry.ts`: `resolveNetwork` + network types (slug map + derived from the registry URLs; to be emitted by ws-tools properly) +- `AlchemyRestClient` is now exported (was written for signer v5 but unexported) + +## Deliberately out of scope (tracked in the data SDK scope plan) + +- Rest client hardening: retries, timeouts, request-id, first-class query params +- Pagination iterators, error normalization, the SDK manifest, remaining methods +- ws-tools generator change to emit `{ slug, chainId, caip2 }` entries + + the `KnownAlchemyNetwork` union + +## Interfaces + +| Interface | Description | +| :------------------------------------------------------------------------------------- | :--------------------------------------------------- | +| [PortfolioAddressEntry](/wallets/reference/data-apis/interfaces/PortfolioAddressEntry) | An address paired with the networks to query it on. | +| [PriceAddressEntry](/wallets/reference/data-apis/interfaces/PriceAddressEntry) | A token address paired with the network it lives on. | + +## Type Aliases + +| Type Alias | Description | +| :----------------------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [AlchemyDataClient](/wallets/reference/data-apis/type-aliases/AlchemyDataClient) | - | +| [AlchemyDataClientOptions](/wallets/reference/data-apis/type-aliases/AlchemyDataClientOptions) | - | +| [AssetTransfer](/wallets/reference/data-apis/type-aliases/AssetTransfer) | - | +| [ComputeRarityParams](/wallets/reference/data-apis/type-aliases/ComputeRarityParams) | - | +| [ComputeRarityResult](/wallets/reference/data-apis/type-aliases/ComputeRarityResult) | - | +| [DataActions](/wallets/reference/data-apis/type-aliases/DataActions) | The namespaced Data API actions attached by the [dataActions](/wallets/reference/data-apis/functions/dataActions) decorator. | +| [DataRpcSchema](/wallets/reference/data-apis/type-aliases/DataRpcSchema) | viem RpcSchema entries for the Data JSON-RPC methods. Attach to a client to get typed `client.request({ method: "alchemy_getAssetTransfers", ... })`. | +| [GetAssetTransfersParams](/wallets/reference/data-apis/type-aliases/GetAssetTransfersParams) | Generated RPC params plus the SDK's network override. | +| [GetAssetTransfersResult](/wallets/reference/data-apis/type-aliases/GetAssetTransfersResult) | The spec result is `oneOf: ["Not Found (null)" string, object]`; the string branch is a docs-spec artifact the SDK deliberately does not surface, so it is collapsed away here (and in [DataRpcSchema](/wallets/reference/data-apis/type-aliases/DataRpcSchema)). | +| [GetCollectionMetadataParams](/wallets/reference/data-apis/type-aliases/GetCollectionMetadataParams) | - | +| [GetCollectionMetadataResult](/wallets/reference/data-apis/type-aliases/GetCollectionMetadataResult) | - | +| [GetCollectionsForOwnerParams](/wallets/reference/data-apis/type-aliases/GetCollectionsForOwnerParams) | - | +| [GetCollectionsForOwnerResult](/wallets/reference/data-apis/type-aliases/GetCollectionsForOwnerResult) | - | +| [GetContractMetadataBatchParams](/wallets/reference/data-apis/type-aliases/GetContractMetadataBatchParams) | - | +| [GetContractMetadataBatchResult](/wallets/reference/data-apis/type-aliases/GetContractMetadataBatchResult) | - | +| [GetContractMetadataParams](/wallets/reference/data-apis/type-aliases/GetContractMetadataParams) | - | +| [GetContractMetadataResult](/wallets/reference/data-apis/type-aliases/GetContractMetadataResult) | - | +| [GetContractsForOwnerParams](/wallets/reference/data-apis/type-aliases/GetContractsForOwnerParams) | - | +| [GetContractsForOwnerResult](/wallets/reference/data-apis/type-aliases/GetContractsForOwnerResult) | - | +| [GetFloorPriceParams](/wallets/reference/data-apis/type-aliases/GetFloorPriceParams) | - | +| [GetFloorPriceResult](/wallets/reference/data-apis/type-aliases/GetFloorPriceResult) | - | +| [GetHistoricalTokenPricesParams](/wallets/reference/data-apis/type-aliases/GetHistoricalTokenPricesParams) | - | +| [GetHistoricalTokenPricesResult](/wallets/reference/data-apis/type-aliases/GetHistoricalTokenPricesResult) | - | +| [GetNftContractsByAddressParams](/wallets/reference/data-apis/type-aliases/GetNftContractsByAddressParams) | - | +| [GetNftContractsByAddressResult](/wallets/reference/data-apis/type-aliases/GetNftContractsByAddressResult) | - | +| [GetNftMetadataBatchParams](/wallets/reference/data-apis/type-aliases/GetNftMetadataBatchParams) | - | +| [GetNftMetadataBatchResult](/wallets/reference/data-apis/type-aliases/GetNftMetadataBatchResult) | - | +| [GetNftMetadataParams](/wallets/reference/data-apis/type-aliases/GetNftMetadataParams) | - | +| [GetNftMetadataResult](/wallets/reference/data-apis/type-aliases/GetNftMetadataResult) | - | +| [GetNftSalesParams](/wallets/reference/data-apis/type-aliases/GetNftSalesParams) | - | +| [GetNftSalesResult](/wallets/reference/data-apis/type-aliases/GetNftSalesResult) | - | +| [GetNftsByAddressParams](/wallets/reference/data-apis/type-aliases/GetNftsByAddressParams) | - | +| [GetNftsByAddressResult](/wallets/reference/data-apis/type-aliases/GetNftsByAddressResult) | - | +| [GetNftsForCollectionParams](/wallets/reference/data-apis/type-aliases/GetNftsForCollectionParams) | - | +| [GetNftsForCollectionResult](/wallets/reference/data-apis/type-aliases/GetNftsForCollectionResult) | - | +| [GetNftsForContractParams](/wallets/reference/data-apis/type-aliases/GetNftsForContractParams) | - | +| [GetNftsForContractResult](/wallets/reference/data-apis/type-aliases/GetNftsForContractResult) | - | +| [GetNftsForOwnerParams](/wallets/reference/data-apis/type-aliases/GetNftsForOwnerParams) | - | +| [GetNftsForOwnerResult](/wallets/reference/data-apis/type-aliases/GetNftsForOwnerResult) | - | +| [GetOwnersForContractParams](/wallets/reference/data-apis/type-aliases/GetOwnersForContractParams) | - | +| [GetOwnersForContractResult](/wallets/reference/data-apis/type-aliases/GetOwnersForContractResult) | - | +| [GetOwnersForNftParams](/wallets/reference/data-apis/type-aliases/GetOwnersForNftParams) | - | +| [GetOwnersForNftResult](/wallets/reference/data-apis/type-aliases/GetOwnersForNftResult) | - | +| [GetSpamContractsParams](/wallets/reference/data-apis/type-aliases/GetSpamContractsParams) | - | +| [GetSpamContractsResult](/wallets/reference/data-apis/type-aliases/GetSpamContractsResult) | - | +| [GetTokenAllowanceParams](/wallets/reference/data-apis/type-aliases/GetTokenAllowanceParams) | - | +| [GetTokenAllowanceResult](/wallets/reference/data-apis/type-aliases/GetTokenAllowanceResult) | - | +| [GetTokenBalancesByAddressParams](/wallets/reference/data-apis/type-aliases/GetTokenBalancesByAddressParams) | - | +| [GetTokenBalancesByAddressResult](/wallets/reference/data-apis/type-aliases/GetTokenBalancesByAddressResult) | - | +| [GetTokenBalancesParams](/wallets/reference/data-apis/type-aliases/GetTokenBalancesParams) | - | +| [GetTokenBalancesResult](/wallets/reference/data-apis/type-aliases/GetTokenBalancesResult) | - | +| [GetTokenMetadataParams](/wallets/reference/data-apis/type-aliases/GetTokenMetadataParams) | - | +| [GetTokenMetadataResult](/wallets/reference/data-apis/type-aliases/GetTokenMetadataResult) | - | +| [GetTokenPricesByAddressParams](/wallets/reference/data-apis/type-aliases/GetTokenPricesByAddressParams) | - | +| [GetTokenPricesByAddressResult](/wallets/reference/data-apis/type-aliases/GetTokenPricesByAddressResult) | - | +| [GetTokenPricesBySymbolParams](/wallets/reference/data-apis/type-aliases/GetTokenPricesBySymbolParams) | Chain-agnostic: token symbols only, no network involved. | +| [GetTokenPricesBySymbolResult](/wallets/reference/data-apis/type-aliases/GetTokenPricesBySymbolResult) | - | +| [GetTokensByAddressParams](/wallets/reference/data-apis/type-aliases/GetTokensByAddressParams) | - | +| [GetTokensByAddressResult](/wallets/reference/data-apis/type-aliases/GetTokensByAddressResult) | - | +| [IsAirdropNftParams](/wallets/reference/data-apis/type-aliases/IsAirdropNftParams) | - | +| [IsAirdropNftResult](/wallets/reference/data-apis/type-aliases/IsAirdropNftResult) | - | +| [IsHolderOfContractParams](/wallets/reference/data-apis/type-aliases/IsHolderOfContractParams) | - | +| [IsHolderOfContractResult](/wallets/reference/data-apis/type-aliases/IsHolderOfContractResult) | - | +| [IsSpamContractParams](/wallets/reference/data-apis/type-aliases/IsSpamContractParams) | - | +| [IsSpamContractResult](/wallets/reference/data-apis/type-aliases/IsSpamContractResult) | - | +| [NftRestSchema](/wallets/reference/data-apis/type-aliases/NftRestSchema) | RestRequestSchema entries for the nft REST API. | +| [PaginateOptions](/wallets/reference/data-apis/type-aliases/PaginateOptions) | Options accepted by the `*Pages` async-iterator actions. | +| [PortfolioRestSchema](/wallets/reference/data-apis/type-aliases/PortfolioRestSchema) | RestRequestSchema entries for the portfolio REST API. | +| [PortfolioToken](/wallets/reference/data-apis/type-aliases/PortfolioToken) | - | +| [PricesRestSchema](/wallets/reference/data-apis/type-aliases/PricesRestSchema) | RestRequestSchema entries for the prices REST API. | +| [RequestOptions](/wallets/reference/data-apis/type-aliases/RequestOptions) | Per-request options accepted by data actions. | +| [SearchContractMetadataParams](/wallets/reference/data-apis/type-aliases/SearchContractMetadataParams) | - | +| [SearchContractMetadataResult](/wallets/reference/data-apis/type-aliases/SearchContractMetadataResult) | - | +| [SummarizeNftAttributesParams](/wallets/reference/data-apis/type-aliases/SummarizeNftAttributesParams) | - | +| [SummarizeNftAttributesResult](/wallets/reference/data-apis/type-aliases/SummarizeNftAttributesResult) | - | + +## Variables + +| Variable | Description | +| :-------------------------------------------------------- | :---------- | +| [VERSION](/wallets/reference/data-apis/variables/VERSION) | - | + +## Functions + +| Function | Description | +| :---------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [computeRarity](/wallets/reference/data-apis/functions/computeRarity) | Computes attribute rarity for a specific NFT. The network is resolved per request: an explicit `network` param wins, otherwise the client's configured network/chain applies. | +| [createDataClient](/wallets/reference/data-apis/functions/createDataClient) | Creates a Data API client. This is a convenience wrapper over `createClient` + `alchemyTransport` + the [dataActions](/wallets/reference/data-apis/functions/dataActions) decorator — developers already holding a viem client with an Alchemy transport can use `client.extend(dataActions)` instead and get the identical behavior. | +| [dataActions](/wallets/reference/data-apis/functions/dataActions) | A viem client decorator that attaches the Data API actions, grouped by namespace, to any client configured with an Alchemy transport. | +| [getAssetTransfers](/wallets/reference/data-apis/functions/getAssetTransfers) | Fetches historical asset transfers (external, internal, token) for the resolved network via the `alchemy_getAssetTransfers` JSON-RPC method. | +| [getAssetTransfersPages](/wallets/reference/data-apis/functions/getAssetTransfersPages) | Auto-paginating companion to [getAssetTransfers](/wallets/reference/data-apis/functions/getAssetTransfers): yields whole pages until the cursor is exhausted (or `maxPages` is hit), guarding against repeated cursors. Note: JSON-RPC requests run through the client's viem transport, which owns the fetch — the abort signal is honored between pages, not mid-request. | +| [getCollectionMetadata](/wallets/reference/data-apis/functions/getCollectionMetadata) | Fetches metadata for an NFT collection by slug. The network is resolved per request: an explicit `network` param wins, otherwise the client's configured network/chain applies. | +| [getCollectionsForOwner](/wallets/reference/data-apis/functions/getCollectionsForOwner) | Fetches all NFT collections an address holds tokens from. The network is resolved per request: an explicit `network` param wins, otherwise the client's configured network/chain applies. | +| [getCollectionsForOwnerPages](/wallets/reference/data-apis/functions/getCollectionsForOwnerPages) | Auto-paginating companion to [getCollectionsForOwner](/wallets/reference/data-apis/functions/getCollectionsForOwner): yields whole pages until the cursor is exhausted (or `maxPages` is hit), guarding against repeated cursors. Iterate items with an inner loop over each page. | +| [getContractMetadata](/wallets/reference/data-apis/functions/getContractMetadata) | Fetches metadata for an NFT contract. The network is resolved per request: an explicit `network` param wins, otherwise the client's configured network/chain applies. | +| [getContractMetadataBatch](/wallets/reference/data-apis/functions/getContractMetadataBatch) | Fetches metadata for multiple NFT contracts in one call. The network is resolved per request: an explicit `network` param wins, otherwise the client's configured network/chain applies. | +| [getContractsForOwner](/wallets/reference/data-apis/functions/getContractsForOwner) | Fetches all NFT contracts an address holds tokens from. The network is resolved per request: an explicit `network` param wins, otherwise the client's configured network/chain applies. | +| [getContractsForOwnerPages](/wallets/reference/data-apis/functions/getContractsForOwnerPages) | Auto-paginating companion to [getContractsForOwner](/wallets/reference/data-apis/functions/getContractsForOwner): yields whole pages until the cursor is exhausted (or `maxPages` is hit), guarding against repeated cursors. Iterate items with an inner loop over each page. | +| [getFloorPrice](/wallets/reference/data-apis/functions/getFloorPrice) | Fetches marketplace floor prices for an NFT contract or collection. The network is resolved per request: an explicit `network` param wins, otherwise the client's configured network/chain applies. | +| [getHistoricalTokenPrices](/wallets/reference/data-apis/functions/getHistoricalTokenPrices) | Fetches historical prices for a token, identified either by symbol (chain-agnostic) or by network + contract address. Runs against the global Prices API; when a network is given it travels in the request body, so the client's chain is not involved. | +| [getNftContractsByAddress](/wallets/reference/data-apis/functions/getNftContractsByAddress) | Fetches NFT contracts for one or more addresses across one or more networks in a single call. This is a multi-network request against the global Data API: networks travel in the request body, so the client's chain is not involved. | +| [getNftContractsByAddressPages](/wallets/reference/data-apis/functions/getNftContractsByAddressPages) | Auto-paginating companion to [getNftContractsByAddress](/wallets/reference/data-apis/functions/getNftContractsByAddress): yields whole pages until the cursor is exhausted (or `maxPages` is hit), guarding against repeated cursors. Iterate items with an inner loop over each page. | +| [getNftMetadata](/wallets/reference/data-apis/functions/getNftMetadata) | Fetches metadata for a single NFT. The network is resolved per request: an explicit `network` param wins, otherwise the client's configured network/chain applies. | +| [getNftMetadataBatch](/wallets/reference/data-apis/functions/getNftMetadataBatch) | Fetches metadata for up to 100 NFTs in one call. The network is resolved per request: an explicit `network` param wins, otherwise the client's configured network/chain applies. | +| [getNftSales](/wallets/reference/data-apis/functions/getNftSales) | Fetches NFT sales matching the given filters. The network is resolved per request: an explicit `network` param wins, otherwise the client's configured network/chain applies. | +| [getNftSalesPages](/wallets/reference/data-apis/functions/getNftSalesPages) | Auto-paginating companion to [getNftSales](/wallets/reference/data-apis/functions/getNftSales): yields whole pages until the cursor is exhausted (or `maxPages` is hit), guarding against repeated cursors. Iterate items with an inner loop over each page. | +| [getNftsByAddress](/wallets/reference/data-apis/functions/getNftsByAddress) | Fetches NFTs for one or more addresses across one or more networks in a single call. This is a multi-network request against the global Data API: networks travel in the request body, so the client's chain is not involved. | +| [getNftsByAddressPages](/wallets/reference/data-apis/functions/getNftsByAddressPages) | Auto-paginating companion to [getNftsByAddress](/wallets/reference/data-apis/functions/getNftsByAddress): yields whole pages until the cursor is exhausted (or `maxPages` is hit), guarding against repeated cursors. Iterate items with an inner loop over each page. | +| [getNftsForCollection](/wallets/reference/data-apis/functions/getNftsForCollection) | Fetches all NFTs for a given collection (by contract address or collection slug). The network is resolved per request: an explicit `network` param wins, otherwise the client's configured network/chain applies. | +| [getNftsForCollectionPages](/wallets/reference/data-apis/functions/getNftsForCollectionPages) | Auto-paginating companion to [getNftsForCollection](/wallets/reference/data-apis/functions/getNftsForCollection): yields whole pages until the cursor is exhausted (or `maxPages` is hit), guarding against repeated cursors. Iterate items with an inner loop over each page. | +| [getNftsForContract](/wallets/reference/data-apis/functions/getNftsForContract) | Fetches all NFTs for a given contract. The network is resolved per request: an explicit `network` param wins, otherwise the client's configured network/chain applies. | +| [getNftsForContractPages](/wallets/reference/data-apis/functions/getNftsForContractPages) | Auto-paginating companion to [getNftsForContract](/wallets/reference/data-apis/functions/getNftsForContract): yields whole pages until the cursor is exhausted (or `maxPages` is hit), guarding against repeated cursors. Iterate items with an inner loop over each page. | +| [getNftsForOwner](/wallets/reference/data-apis/functions/getNftsForOwner) | Fetches NFTs owned by an address on a single network. The network is resolved per request: an explicit `network` param wins, otherwise the client's configured network/chain applies. | +| [getNftsForOwnerPages](/wallets/reference/data-apis/functions/getNftsForOwnerPages) | Auto-paginating companion to [getNftsForOwner](/wallets/reference/data-apis/functions/getNftsForOwner): yields whole pages until the cursor is exhausted (or `maxPages` is hit), guarding against repeated cursors. Iterate items with an inner loop over each page. | +| [getOwnersForContract](/wallets/reference/data-apis/functions/getOwnersForContract) | Fetches all owners for an NFT contract. The network is resolved per request: an explicit `network` param wins, otherwise the client's configured network/chain applies. | +| [getOwnersForNft](/wallets/reference/data-apis/functions/getOwnersForNft) | Fetches the owners of a specific NFT. The network is resolved per request: an explicit `network` param wins, otherwise the client's configured network/chain applies. | +| [getSpamContracts](/wallets/reference/data-apis/functions/getSpamContracts) | Fetches the full list of contracts classified as spam on a network. The network is resolved per request: an explicit `network` param wins, otherwise the client's configured network/chain applies. | +| [getTokenAllowance](/wallets/reference/data-apis/functions/getTokenAllowance) | Fetches the ERC-20 allowance a spender has from an owner via the `alchemy_getTokenAllowance` JSON-RPC method. Without a `network` override this uses the client's transport; with one, a transport instance is derived for the override network. | +| [getTokenBalances](/wallets/reference/data-apis/functions/getTokenBalances) | Fetches ERC-20 (and native) token balances for an address via the `alchemy_getTokenBalances` JSON-RPC method. Without a `network` override this uses the client's transport; with one, a transport instance is derived for the override network. | +| [getTokenBalancesByAddress](/wallets/reference/data-apis/functions/getTokenBalancesByAddress) | Fetches token balances (without metadata or prices) for one or more addresses across one or more networks in a single call. This is a multi-network request against the global Data API: networks travel in the request body, so the client's chain is not involved. | +| [getTokenMetadata](/wallets/reference/data-apis/functions/getTokenMetadata) | Fetches metadata (name, symbol, decimals, logo) for a token contract via the `alchemy_getTokenMetadata` JSON-RPC method. Without a `network` override this uses the client's transport; with one, a transport instance is derived for the override network. | +| [getTokenPricesByAddress](/wallets/reference/data-apis/functions/getTokenPricesByAddress) | Fetches current prices for tokens by contract address (max 25 pairs). This is a multi-network request against the global Prices API: each entry pairs an address with its network, so the client's chain is not involved. | +| [getTokenPricesBySymbol](/wallets/reference/data-apis/functions/getTokenPricesBySymbol) | Fetches current prices for tokens by symbol (max 25). This is a chain-agnostic request against the global Prices API — no network is involved at all. | +| [getTokensByAddress](/wallets/reference/data-apis/functions/getTokensByAddress) | Fetches tokens (with optional metadata and prices) for one or more addresses across one or more networks in a single call. This is a multi-network request against the global Data API: networks travel in the request body, so the client's chain is not involved. | +| [isAirdropNft](/wallets/reference/data-apis/functions/isAirdropNft) | Checks whether an NFT was airdropped to its owner. The network is resolved per request: an explicit `network` param wins, otherwise the client's configured network/chain applies. | +| [isHolderOfContract](/wallets/reference/data-apis/functions/isHolderOfContract) | Checks whether a wallet holds any NFT from a contract. The network is resolved per request: an explicit `network` param wins, otherwise the client's configured network/chain applies. | +| [isSpamContract](/wallets/reference/data-apis/functions/isSpamContract) | Checks whether a contract is classified as spam. The network is resolved per request: an explicit `network` param wins, otherwise the client's configured network/chain applies. | +| [searchContractMetadata](/wallets/reference/data-apis/functions/searchContractMetadata) | Searches NFT contract metadata by keyword. The network is resolved per request: an explicit `network` param wins, otherwise the client's configured network/chain applies. | +| [summarizeNftAttributes](/wallets/reference/data-apis/functions/summarizeNftAttributes) | Summarizes attribute prevalence for an NFT contract. The network is resolved per request: an explicit `network` param wins, otherwise the client's configured network/chain applies. | diff --git a/docs/pages/reference/data-apis/src/functions/computeRarity.mdx b/docs/pages/reference/data-apis/src/functions/computeRarity.mdx new file mode 100644 index 0000000000..451a61fd74 --- /dev/null +++ b/docs/pages/reference/data-apis/src/functions/computeRarity.mdx @@ -0,0 +1,89 @@ +--- +title: computeRarity +description: Overview of the computeRarity function +slug: wallets/reference/data-apis/functions/computeRarity +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +function computeRarity( + client, + params, + options?, +): Promise<{ + rarities?: object[]; +}>; +``` + +Defined in: [packages/data-apis/src/actions/nft/computeRarity.ts:21](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/actions/nft/computeRarity.ts#L21) + +Computes attribute rarity for a specific NFT. The network is resolved per +request: an explicit `network` param wins, otherwise the client's +configured network/chain applies. + +## Parameters + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
+ `client` + + `DataClient` + + A client configured with an Alchemy transport +
+ `params` + + [`ComputeRarityParams`](../type-aliases/ComputeRarityParams) + + Contract address, token id, and optional network override +
+ `options?` + + [`RequestOptions`](../type-aliases/RequestOptions) + + Per-request options (abort signal) +
+ +## Returns + +`Promise`\<\{ +`rarities?`: `object`\[]; +}> + +Rarity scores per attribute diff --git a/docs/pages/reference/data-apis/src/functions/createDataClient.mdx b/docs/pages/reference/data-apis/src/functions/createDataClient.mdx new file mode 100644 index 0000000000..5b239f6298 --- /dev/null +++ b/docs/pages/reference/data-apis/src/functions/createDataClient.mdx @@ -0,0 +1,67 @@ +--- +title: createDataClient +description: Overview of the createDataClient function +slug: wallets/reference/data-apis/functions/createDataClient +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +function createDataClient(options): AlchemyDataClient; +``` + +Defined in: [packages/data-apis/src/client.ts:49](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/client.ts#L49) + +Creates a Data API client. This is a convenience wrapper over +`createClient` + `alchemyTransport` + the [dataActions](dataActions) decorator — +developers already holding a viem client with an Alchemy transport can use +`client.extend(dataActions)` instead and get the identical behavior. + +## Example + +```ts +import { createDataClient } from "@alchemy/data-apis"; + +const data = createDataClient({ + apiKey: process.env.ALCHEMY_API_KEY, + network: "eth-mainnet", // or `mainnet` from viem/chains, or "eip155:1" +}); + +const nfts = await data.nft.getNftsForOwner({ owner: "0x..." }); +``` + +## Parameters + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
+ `options` + + [`AlchemyDataClientOptions`](../type-aliases/AlchemyDataClientOptions) + + Auth (apiKey/jwt/proxy url) and default network +
+ +## Returns + +[`AlchemyDataClient`](../type-aliases/AlchemyDataClient) + +A viem client extended with the Data API actions diff --git a/docs/pages/reference/data-apis/src/functions/dataActions.mdx b/docs/pages/reference/data-apis/src/functions/dataActions.mdx new file mode 100644 index 0000000000..2e331ef7f0 --- /dev/null +++ b/docs/pages/reference/data-apis/src/functions/dataActions.mdx @@ -0,0 +1,68 @@ +--- +title: dataActions +description: Overview of the dataActions function +slug: wallets/reference/data-apis/functions/dataActions +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +function dataActions(client): DataActions; +``` + +Defined in: [packages/data-apis/src/decorator.ts:236](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/decorator.ts#L236) + +A viem client decorator that attaches the Data API actions, grouped by +namespace, to any client configured with an Alchemy transport. + +## Example + +```ts +import { createClient } from "viem"; +import { mainnet } from "viem/chains"; +import { alchemyTransport } from "@alchemy/common"; +import { dataActions } from "@alchemy/data-apis"; + +const client = createClient({ + chain: mainnet, + transport: alchemyTransport({ apiKey: "..." }), +}).extend(dataActions); + +const nfts = await client.nft.getNftsForOwner({ owner: "0x..." }); +``` + +## Parameters + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
+ `client` + + `DataClient` + + The client to decorate +
+ +## Returns + +[`DataActions`](../type-aliases/DataActions) + +The namespaced Data API actions diff --git a/docs/pages/reference/data-apis/src/functions/getAssetTransfers.mdx b/docs/pages/reference/data-apis/src/functions/getAssetTransfers.mdx new file mode 100644 index 0000000000..0827b8b112 --- /dev/null +++ b/docs/pages/reference/data-apis/src/functions/getAssetTransfers.mdx @@ -0,0 +1,80 @@ +--- +title: getAssetTransfers +description: Overview of the getAssetTransfers function +slug: wallets/reference/data-apis/functions/getAssetTransfers +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +function getAssetTransfers( + client, + params, +): Promise<{ + pageKey?: string; + transfers?: object[]; +}>; +``` + +Defined in: [packages/data-apis/src/actions/transfers/getAssetTransfers.ts:24](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/actions/transfers/getAssetTransfers.ts#L24) + +Fetches historical asset transfers (external, internal, token) for the +resolved network via the `alchemy_getAssetTransfers` JSON-RPC method. + +Without a `network` override this is a plain viem action over the client's +Alchemy transport. With an override, a transport instance is derived from +the client's transport config and pointed at the override network's RPC URL +— the same mechanism the transport's tracing support uses. + +## Parameters + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
+ `client` + + `DataClient` + + A client configured with an Alchemy transport +
+ `params` + + [`GetAssetTransfersParams`](../type-aliases/GetAssetTransfersParams) + + Transfer filters and optional network override +
+ +## Returns + +`Promise`\<\{ +`pageKey?`: `string`; +`transfers?`: `object`\[]; +}> + +The matching transfers and pagination cursor diff --git a/docs/pages/reference/data-apis/src/functions/getAssetTransfersPages.mdx b/docs/pages/reference/data-apis/src/functions/getAssetTransfersPages.mdx new file mode 100644 index 0000000000..7c3616f3bb --- /dev/null +++ b/docs/pages/reference/data-apis/src/functions/getAssetTransfersPages.mdx @@ -0,0 +1,97 @@ +--- +title: getAssetTransfersPages +description: Overview of the getAssetTransfersPages function +slug: wallets/reference/data-apis/functions/getAssetTransfersPages +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +function getAssetTransfersPages( + client, + params, + options?, +): AsyncGenerator< + { + pageKey?: string; + transfers?: object[]; + }, + void, + undefined +>; +``` + +Defined in: [packages/data-apis/src/actions/transfers/getAssetTransfersPages.ts:21](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/actions/transfers/getAssetTransfersPages.ts#L21) + +Auto-paginating companion to [getAssetTransfers](getAssetTransfers): yields whole pages +until the cursor is exhausted (or `maxPages` is hit), guarding against +repeated cursors. Note: JSON-RPC requests run through the client's viem +transport, which owns the fetch — the abort signal is honored between +pages, not mid-request. + +## Parameters + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
+ `client` + + `DataClient` + + A client configured with an Alchemy transport +
+ `params` + + [`GetAssetTransfersParams`](../type-aliases/GetAssetTransfersParams) + + Same params as getAssetTransfers (the cursor is managed for you) +
+ `options?` + + [`PaginateOptions`](../type-aliases/PaginateOptions) + + Abort signal (checked between pages) and page cap +
+ +## Returns + +`AsyncGenerator`\<\{ +`pageKey?`: `string`; +`transfers?`: `object`\[]; +}, `void`, `undefined`> + +Pages, in order diff --git a/docs/pages/reference/data-apis/src/functions/getCollectionMetadata.mdx b/docs/pages/reference/data-apis/src/functions/getCollectionMetadata.mdx new file mode 100644 index 0000000000..100c03a4cb --- /dev/null +++ b/docs/pages/reference/data-apis/src/functions/getCollectionMetadata.mdx @@ -0,0 +1,109 @@ +--- +title: getCollectionMetadata +description: Overview of the getCollectionMetadata function +slug: wallets/reference/data-apis/functions/getCollectionMetadata +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +function getCollectionMetadata( + client, + params, + options?, +): Promise<{ + description?: string; + discordUrl?: string; + externalUrl?: string; + floorPrice?: { + floorPrice?: number; + marketplace?: string; + priceCurrency?: string; + }; + name?: string; + slug?: string; + twitterUsername?: string; +}>; +``` + +Defined in: [packages/data-apis/src/actions/nft/getCollectionMetadata.ts:24](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/actions/nft/getCollectionMetadata.ts#L24) + +Fetches metadata for an NFT collection by slug. The network is resolved per +request: an explicit `network` param wins, otherwise the client's +configured network/chain applies. + +## Parameters + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
+ `client` + + `DataClient` + + A client configured with an Alchemy transport +
+ `params` + + [`GetCollectionMetadataParams`](../type-aliases/GetCollectionMetadataParams) + + Collection slug and optional network override +
+ `options?` + + [`RequestOptions`](../type-aliases/RequestOptions) + + Per-request options (abort signal) +
+ +## Returns + +`Promise`\<\{ +`description?`: `string`; +`discordUrl?`: `string`; +`externalUrl?`: `string`; +`floorPrice?`: \{ +`floorPrice?`: `number`; +`marketplace?`: `string`; +`priceCurrency?`: `string`; +}; +`name?`: `string`; +`slug?`: `string`; +`twitterUsername?`: `string`; +}> + +The collection's metadata diff --git a/docs/pages/reference/data-apis/src/functions/getCollectionsForOwner.mdx b/docs/pages/reference/data-apis/src/functions/getCollectionsForOwner.mdx new file mode 100644 index 0000000000..9207e8d305 --- /dev/null +++ b/docs/pages/reference/data-apis/src/functions/getCollectionsForOwner.mdx @@ -0,0 +1,93 @@ +--- +title: getCollectionsForOwner +description: Overview of the getCollectionsForOwner function +slug: wallets/reference/data-apis/functions/getCollectionsForOwner +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +function getCollectionsForOwner( + client, + params, + options?, +): Promise<{ + collections?: object[]; + pageKey?: string; + totalCount?: string; +}>; +``` + +Defined in: [packages/data-apis/src/actions/nft/getCollectionsForOwner.ts:26](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/actions/nft/getCollectionsForOwner.ts#L26) + +Fetches all NFT collections an address holds tokens from. The network is +resolved per request: an explicit `network` param wins, otherwise the +client's configured network/chain applies. + +## Parameters + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
+ `client` + + `DataClient` + + A client configured with an Alchemy transport +
+ `params` + + [`GetCollectionsForOwnerParams`](../type-aliases/GetCollectionsForOwnerParams) + + Owner address, optional network override, and filters +
+ `options?` + + [`RequestOptions`](../type-aliases/RequestOptions) + + Per-request options (abort signal) +
+ +## Returns + +`Promise`\<\{ +`collections?`: `object`\[]; +`pageKey?`: `string`; +`totalCount?`: `string`; +}> + +The owned collections and pagination cursor diff --git a/docs/pages/reference/data-apis/src/functions/getCollectionsForOwnerPages.mdx b/docs/pages/reference/data-apis/src/functions/getCollectionsForOwnerPages.mdx new file mode 100644 index 0000000000..59565ddc4c --- /dev/null +++ b/docs/pages/reference/data-apis/src/functions/getCollectionsForOwnerPages.mdx @@ -0,0 +1,97 @@ +--- +title: getCollectionsForOwnerPages +description: Overview of the getCollectionsForOwnerPages function +slug: wallets/reference/data-apis/functions/getCollectionsForOwnerPages +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +function getCollectionsForOwnerPages( + client, + params, + options?, +): AsyncGenerator< + { + collections?: object[]; + pageKey?: string; + totalCount?: string; + }, + void, + undefined +>; +``` + +Defined in: [packages/data-apis/src/actions/nft/getCollectionsForOwnerPages.ts:19](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/actions/nft/getCollectionsForOwnerPages.ts#L19) + +Auto-paginating companion to [getCollectionsForOwner](getCollectionsForOwner): yields whole pages until the +cursor is exhausted (or `maxPages` is hit), guarding against repeated +cursors. Iterate items with an inner loop over each page. + +## Parameters + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
+ `client` + + `DataClient` + + A client configured with an Alchemy transport +
+ `params` + + [`GetCollectionsForOwnerParams`](../type-aliases/GetCollectionsForOwnerParams) + + Same params as getCollectionsForOwner (the cursor is managed for you) +
+ `options?` + + [`PaginateOptions`](../type-aliases/PaginateOptions) + + Abort signal and page cap +
+ +## Returns + +`AsyncGenerator`\<\{ +`collections?`: `object`\[]; +`pageKey?`: `string`; +`totalCount?`: `string`; +}, `void`, `undefined`> + +Pages, in order diff --git a/docs/pages/reference/data-apis/src/functions/getContractMetadata.mdx b/docs/pages/reference/data-apis/src/functions/getContractMetadata.mdx new file mode 100644 index 0000000000..bb8ecc5d8f --- /dev/null +++ b/docs/pages/reference/data-apis/src/functions/getContractMetadata.mdx @@ -0,0 +1,129 @@ +--- +title: getContractMetadata +description: Overview of the getContractMetadata function +slug: wallets/reference/data-apis/functions/getContractMetadata +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +function getContractMetadata( + client, + params, + options?, +): Promise<{ + address?: string; + contractDeployer?: string; + deployedBlockNumber?: number; + name?: string; + openseaMetadata?: { + bannerImageUrl?: string; + collectionName?: string; + description?: string; + discordUrl?: string; + externalUrl?: string; + floorPrice?: number; + imageUrl?: string; + lastIngestedAt?: string; + safelistRequestStatus?: string; + twitterUsername?: string; + }; + symbol?: string; + tokenType?: + | "ERC721" + | "ERC1155" + | "NO_SUPPORTED_NFT_STANDARD" + | "NOT_A_CONTRACT"; + totalSupply?: string; +}>; +``` + +Defined in: [packages/data-apis/src/actions/nft/getContractMetadata.ts:24](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/actions/nft/getContractMetadata.ts#L24) + +Fetches metadata for an NFT contract. The network is resolved per +request: an explicit `network` param wins, otherwise the client's +configured network/chain applies. + +## Parameters + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
+ `client` + + `DataClient` + + A client configured with an Alchemy transport +
+ `params` + + [`GetContractMetadataParams`](../type-aliases/GetContractMetadataParams) + + Contract address and optional network override +
+ `options?` + + [`RequestOptions`](../type-aliases/RequestOptions) + + Per-request options (abort signal) +
+ +## Returns + +`Promise`\<\{ +`address?`: `string`; +`contractDeployer?`: `string`; +`deployedBlockNumber?`: `number`; +`name?`: `string`; +`openseaMetadata?`: \{ +`bannerImageUrl?`: `string`; +`collectionName?`: `string`; +`description?`: `string`; +`discordUrl?`: `string`; +`externalUrl?`: `string`; +`floorPrice?`: `number`; +`imageUrl?`: `string`; +`lastIngestedAt?`: `string`; +`safelistRequestStatus?`: `string`; +`twitterUsername?`: `string`; +}; +`symbol?`: `string`; +`tokenType?`: `"ERC721"` | `"ERC1155"` | `"NO_SUPPORTED_NFT_STANDARD"` | `"NOT_A_CONTRACT"`; +`totalSupply?`: `string`; +}> + +The contract's metadata diff --git a/docs/pages/reference/data-apis/src/functions/getContractMetadataBatch.mdx b/docs/pages/reference/data-apis/src/functions/getContractMetadataBatch.mdx new file mode 100644 index 0000000000..b0fe8c2708 --- /dev/null +++ b/docs/pages/reference/data-apis/src/functions/getContractMetadataBatch.mdx @@ -0,0 +1,81 @@ +--- +title: getContractMetadataBatch +description: Overview of the getContractMetadataBatch function +slug: wallets/reference/data-apis/functions/getContractMetadataBatch +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +function getContractMetadataBatch(client, params, options?): Promise; +``` + +Defined in: [packages/data-apis/src/actions/nft/getContractMetadataBatch.ts:24](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/actions/nft/getContractMetadataBatch.ts#L24) + +Fetches metadata for multiple NFT contracts in one call. The network is +resolved per request: an explicit `network` param wins, otherwise the +client's configured network/chain applies. + +## Parameters + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
+ `client` + + `DataClient` + + A client configured with an Alchemy transport +
+ `params` + + [`GetContractMetadataBatchParams`](../type-aliases/GetContractMetadataBatchParams) + + The contract addresses and optional network override +
+ `options?` + + [`RequestOptions`](../type-aliases/RequestOptions) + + Per-request options (abort signal) +
+ +## Returns + +`Promise`\<`object`\[]> + +Metadata for each requested contract diff --git a/docs/pages/reference/data-apis/src/functions/getContractsForOwner.mdx b/docs/pages/reference/data-apis/src/functions/getContractsForOwner.mdx new file mode 100644 index 0000000000..acea551e81 --- /dev/null +++ b/docs/pages/reference/data-apis/src/functions/getContractsForOwner.mdx @@ -0,0 +1,93 @@ +--- +title: getContractsForOwner +description: Overview of the getContractsForOwner function +slug: wallets/reference/data-apis/functions/getContractsForOwner +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +function getContractsForOwner( + client, + params, + options?, +): Promise<{ + contracts?: object[]; + pageKey?: string; + totalCount?: string; +}>; +``` + +Defined in: [packages/data-apis/src/actions/nft/getContractsForOwner.ts:26](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/actions/nft/getContractsForOwner.ts#L26) + +Fetches all NFT contracts an address holds tokens from. The network is +resolved per request: an explicit `network` param wins, otherwise the +client's configured network/chain applies. + +## Parameters + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
+ `client` + + `DataClient` + + A client configured with an Alchemy transport +
+ `params` + + [`GetContractsForOwnerParams`](../type-aliases/GetContractsForOwnerParams) + + Owner address, optional network override, and filters +
+ `options?` + + [`RequestOptions`](../type-aliases/RequestOptions) + + Per-request options (abort signal) +
+ +## Returns + +`Promise`\<\{ +`contracts?`: `object`\[]; +`pageKey?`: `string`; +`totalCount?`: `string`; +}> + +The owned contracts and pagination cursor diff --git a/docs/pages/reference/data-apis/src/functions/getContractsForOwnerPages.mdx b/docs/pages/reference/data-apis/src/functions/getContractsForOwnerPages.mdx new file mode 100644 index 0000000000..3df452f6db --- /dev/null +++ b/docs/pages/reference/data-apis/src/functions/getContractsForOwnerPages.mdx @@ -0,0 +1,97 @@ +--- +title: getContractsForOwnerPages +description: Overview of the getContractsForOwnerPages function +slug: wallets/reference/data-apis/functions/getContractsForOwnerPages +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +function getContractsForOwnerPages( + client, + params, + options?, +): AsyncGenerator< + { + contracts?: object[]; + pageKey?: string; + totalCount?: string; + }, + void, + undefined +>; +``` + +Defined in: [packages/data-apis/src/actions/nft/getContractsForOwnerPages.ts:19](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/actions/nft/getContractsForOwnerPages.ts#L19) + +Auto-paginating companion to [getContractsForOwner](getContractsForOwner): yields whole pages until the +cursor is exhausted (or `maxPages` is hit), guarding against repeated +cursors. Iterate items with an inner loop over each page. + +## Parameters + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
+ `client` + + `DataClient` + + A client configured with an Alchemy transport +
+ `params` + + [`GetContractsForOwnerParams`](../type-aliases/GetContractsForOwnerParams) + + Same params as getContractsForOwner (the cursor is managed for you) +
+ `options?` + + [`PaginateOptions`](../type-aliases/PaginateOptions) + + Abort signal and page cap +
+ +## Returns + +`AsyncGenerator`\<\{ +`contracts?`: `object`\[]; +`pageKey?`: `string`; +`totalCount?`: `string`; +}, `void`, `undefined`> + +Pages, in order diff --git a/docs/pages/reference/data-apis/src/functions/getFloorPrice.mdx b/docs/pages/reference/data-apis/src/functions/getFloorPrice.mdx new file mode 100644 index 0000000000..6fd5ca4218 --- /dev/null +++ b/docs/pages/reference/data-apis/src/functions/getFloorPrice.mdx @@ -0,0 +1,101 @@ +--- +title: getFloorPrice +description: Overview of the getFloorPrice function +slug: wallets/reference/data-apis/functions/getFloorPrice +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +function getFloorPrice( + client, + params, + options?, +): Promise<{ + nftMarketplaceName?: { + collectionUrl?: string; + error?: string; + floorPrice?: number; + priceCurrency?: "ETH"; + retrievedAt?: string; + }; +}>; +``` + +Defined in: [packages/data-apis/src/actions/nft/getFloorPrice.ts:21](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/actions/nft/getFloorPrice.ts#L21) + +Fetches marketplace floor prices for an NFT contract or collection. The network is resolved per +request: an explicit `network` param wins, otherwise the client's +configured network/chain applies. + +## Parameters + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
+ `client` + + `DataClient` + + A client configured with an Alchemy transport +
+ `params` + + [`GetFloorPriceParams`](../type-aliases/GetFloorPriceParams) + + Contract address or collection slug, and optional network override +
+ `options?` + + [`RequestOptions`](../type-aliases/RequestOptions) + + Per-request options (abort signal) +
+ +## Returns + +`Promise`\<\{ +`nftMarketplaceName?`: \{ +`collectionUrl?`: `string`; +`error?`: `string`; +`floorPrice?`: `number`; +`priceCurrency?`: `"ETH"`; +`retrievedAt?`: `string`; +}; +}> + +Floor prices per marketplace diff --git a/docs/pages/reference/data-apis/src/functions/getHistoricalTokenPrices.mdx b/docs/pages/reference/data-apis/src/functions/getHistoricalTokenPrices.mdx new file mode 100644 index 0000000000..752a2faed2 --- /dev/null +++ b/docs/pages/reference/data-apis/src/functions/getHistoricalTokenPrices.mdx @@ -0,0 +1,109 @@ +--- +title: getHistoricalTokenPrices +description: Overview of the getHistoricalTokenPrices function +slug: wallets/reference/data-apis/functions/getHistoricalTokenPrices +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +function getHistoricalTokenPrices( + client, + params, + options?, +): Promise< + | { + currency: string; + data: object[]; + symbol: string; + } + | { + address: string; + currency: string; + data: object[]; + network: string; + } +>; +``` + +Defined in: [packages/data-apis/src/actions/prices/getHistoricalTokenPrices.ts:26](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/actions/prices/getHistoricalTokenPrices.ts#L26) + +Fetches historical prices for a token, identified either by symbol +(chain-agnostic) or by network + contract address. Runs against the global +Prices API; when a network is given it travels in the request body, so the +client's chain is not involved. + +## Parameters + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
+ `client` + + `DataClient` + + A client configured with an Alchemy transport +
+ `params` + + [`GetHistoricalTokenPricesParams`](../type-aliases/GetHistoricalTokenPricesParams) + + Token identifier, time range, and interval +
+ `options?` + + [`RequestOptions`](../type-aliases/RequestOptions) + + Per-request options (abort signal) +
+ +## Returns + +`Promise`\< +| \{ +`currency`: `string`; +`data`: `object`\[]; +`symbol`: `string`; +} +| \{ +`address`: `string`; +`currency`: `string`; +`data`: `object`\[]; +`network`: `string`; +}> + +The price series diff --git a/docs/pages/reference/data-apis/src/functions/getNftContractsByAddress.mdx b/docs/pages/reference/data-apis/src/functions/getNftContractsByAddress.mdx new file mode 100644 index 0000000000..a93e254087 --- /dev/null +++ b/docs/pages/reference/data-apis/src/functions/getNftContractsByAddress.mdx @@ -0,0 +1,98 @@ +--- +title: getNftContractsByAddress +description: Overview of the getNftContractsByAddress function +slug: wallets/reference/data-apis/functions/getNftContractsByAddress +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +function getNftContractsByAddress( + client, + params, + options?, +): Promise<{ + data: { + contracts?: object[]; + pageKey?: string; + totalCount?: number; + }; +}>; +``` + +Defined in: [packages/data-apis/src/actions/portfolio/getNftContractsByAddress.ts:26](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/actions/portfolio/getNftContractsByAddress.ts#L26) + +Fetches NFT contracts for one or more addresses across one or more +networks in a single call. +This is a multi-network request against the global Data API: networks +travel in the request body, so the client's chain is not involved. + +## Parameters + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
+ `client` + + `DataClient` + + A client configured with an Alchemy transport +
+ `params` + + [`GetNftContractsByAddressParams`](../type-aliases/GetNftContractsByAddressParams) + + Addresses paired with networks, plus options +
+ `options?` + + [`RequestOptions`](../type-aliases/RequestOptions) + + Per-request options (abort signal) +
+ +## Returns + +`Promise`\<\{ +`data`: \{ +`contracts?`: `object`\[]; +`pageKey?`: `string`; +`totalCount?`: `number`; +}; +}> + +The owned NFT contracts and pagination cursor diff --git a/docs/pages/reference/data-apis/src/functions/getNftContractsByAddressPages.mdx b/docs/pages/reference/data-apis/src/functions/getNftContractsByAddressPages.mdx new file mode 100644 index 0000000000..97e927cbeb --- /dev/null +++ b/docs/pages/reference/data-apis/src/functions/getNftContractsByAddressPages.mdx @@ -0,0 +1,101 @@ +--- +title: getNftContractsByAddressPages +description: Overview of the getNftContractsByAddressPages function +slug: wallets/reference/data-apis/functions/getNftContractsByAddressPages +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +function getNftContractsByAddressPages( + client, + params, + options?, +): AsyncGenerator< + { + data: { + contracts?: object[]; + pageKey?: string; + totalCount?: number; + }; + }, + void, + undefined +>; +``` + +Defined in: [packages/data-apis/src/actions/portfolio/getNftContractsByAddressPages.ts:19](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/actions/portfolio/getNftContractsByAddressPages.ts#L19) + +Auto-paginating companion to [getNftContractsByAddress](getNftContractsByAddress): yields whole pages until the +cursor is exhausted (or `maxPages` is hit), guarding against repeated +cursors. Iterate items with an inner loop over each page. + +## Parameters + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
+ `client` + + `DataClient` + + A client configured with an Alchemy transport +
+ `params` + + [`GetNftContractsByAddressParams`](../type-aliases/GetNftContractsByAddressParams) + + Same params as getNftContractsByAddress (the cursor is managed for you) +
+ `options?` + + [`PaginateOptions`](../type-aliases/PaginateOptions) + + Abort signal and page cap +
+ +## Returns + +`AsyncGenerator`\<\{ +`data`: \{ +`contracts?`: `object`\[]; +`pageKey?`: `string`; +`totalCount?`: `number`; +}; +}, `void`, `undefined`> + +Pages, in order diff --git a/docs/pages/reference/data-apis/src/functions/getNftMetadata.mdx b/docs/pages/reference/data-apis/src/functions/getNftMetadata.mdx new file mode 100644 index 0000000000..6c089334d4 --- /dev/null +++ b/docs/pages/reference/data-apis/src/functions/getNftMetadata.mdx @@ -0,0 +1,231 @@ +--- +title: getNftMetadata +description: Overview of the getNftMetadata function +slug: wallets/reference/data-apis/functions/getNftMetadata +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +function getNftMetadata( + client, + params, + options?, +): Promise<{ + acquiredAt?: { + blockNumber?: string; + blockTimestamp?: string; + }; + animation?: { + cachedUrl?: string; + contentType?: string; + orginalUrl?: string; + size?: number; + }; + collection?: { + bannerImageUrl?: string; + externalUrl?: string; + name?: string; + slug?: string; + }; + contract?: { + address?: string; + contractDeployer?: string; + deployedBlockNumber?: number; + isSpam?: string; + name?: string; + openseaMetadata?: { + bannerImageUrl?: string; + collectionName?: string; + description?: string; + discordUrl?: string; + externalUrl?: string; + floorPrice?: number; + imageUrl?: string; + lastIngestedAt?: string; + safelistRequestStatus?: string; + twitterUsername?: string; + }; + spamClassifications?: string[]; + symbol?: string; + tokenType?: + | "ERC721" + | "ERC1155" + | "NO_SUPPORTED_NFT_STANDARD" + | "NOT_A_CONTRACT"; + totalSupply?: string; + }; + description?: string; + image?: { + cachedUrl?: string; + contentType?: string; + originalUrl?: string; + pngUrl?: string; + size?: number; + thumbnailUrl?: string; + }; + mint?: { + blockNumber?: number; + mintAddress?: string; + timestamp?: string; + transactionHash?: string; + }; + name?: string; + owners?: string[]; + raw?: { + error?: string; + metadata?: { + attributes?: object[]; + description?: string; + image?: string; + name?: string; + }; + tokenUri?: string; + }; + timeLastUpdated?: string; + tokenId: string; + tokenType?: string; + tokenUri?: string; +}>; +``` + +Defined in: [packages/data-apis/src/actions/nft/getNftMetadata.ts:24](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/actions/nft/getNftMetadata.ts#L24) + +Fetches metadata for a single NFT. The network is resolved per +request: an explicit `network` param wins, otherwise the client's +configured network/chain applies. + +## Parameters + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
+ `client` + + `DataClient` + + A client configured with an Alchemy transport +
+ `params` + + [`GetNftMetadataParams`](../type-aliases/GetNftMetadataParams) + + Contract address, token id, optional network override, and cache options +
+ `options?` + + [`RequestOptions`](../type-aliases/RequestOptions) + + Per-request options (abort signal) +
+ +## Returns + +`Promise`\<\{ +`acquiredAt?`: \{ +`blockNumber?`: `string`; +`blockTimestamp?`: `string`; +}; +`animation?`: \{ +`cachedUrl?`: `string`; +`contentType?`: `string`; +`orginalUrl?`: `string`; +`size?`: `number`; +}; +`collection?`: \{ +`bannerImageUrl?`: `string`; +`externalUrl?`: `string`; +`name?`: `string`; +`slug?`: `string`; +}; +`contract?`: \{ +`address?`: `string`; +`contractDeployer?`: `string`; +`deployedBlockNumber?`: `number`; +`isSpam?`: `string`; +`name?`: `string`; +`openseaMetadata?`: \{ +`bannerImageUrl?`: `string`; +`collectionName?`: `string`; +`description?`: `string`; +`discordUrl?`: `string`; +`externalUrl?`: `string`; +`floorPrice?`: `number`; +`imageUrl?`: `string`; +`lastIngestedAt?`: `string`; +`safelistRequestStatus?`: `string`; +`twitterUsername?`: `string`; +}; +`spamClassifications?`: `string`\[]; +`symbol?`: `string`; +`tokenType?`: `"ERC721"` | `"ERC1155"` | `"NO_SUPPORTED_NFT_STANDARD"` | `"NOT_A_CONTRACT"`; +`totalSupply?`: `string`; +}; +`description?`: `string`; +`image?`: \{ +`cachedUrl?`: `string`; +`contentType?`: `string`; +`originalUrl?`: `string`; +`pngUrl?`: `string`; +`size?`: `number`; +`thumbnailUrl?`: `string`; +}; +`mint?`: \{ +`blockNumber?`: `number`; +`mintAddress?`: `string`; +`timestamp?`: `string`; +`transactionHash?`: `string`; +}; +`name?`: `string`; +`owners?`: `string`\[]; +`raw?`: \{ +`error?`: `string`; +`metadata?`: \{ +`attributes?`: `object`\[]; +`description?`: `string`; +`image?`: `string`; +`name?`: `string`; +}; +`tokenUri?`: `string`; +}; +`timeLastUpdated?`: `string`; +`tokenId`: `string`; +`tokenType?`: `string`; +`tokenUri?`: `string`; +}> + +The NFT's metadata diff --git a/docs/pages/reference/data-apis/src/functions/getNftMetadataBatch.mdx b/docs/pages/reference/data-apis/src/functions/getNftMetadataBatch.mdx new file mode 100644 index 0000000000..68aad57942 --- /dev/null +++ b/docs/pages/reference/data-apis/src/functions/getNftMetadataBatch.mdx @@ -0,0 +1,81 @@ +--- +title: getNftMetadataBatch +description: Overview of the getNftMetadataBatch function +slug: wallets/reference/data-apis/functions/getNftMetadataBatch +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +function getNftMetadataBatch(client, params, options?): Promise; +``` + +Defined in: [packages/data-apis/src/actions/nft/getNftMetadataBatch.ts:24](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/actions/nft/getNftMetadataBatch.ts#L24) + +Fetches metadata for up to 100 NFTs in one call. The network is resolved +per request: an explicit `network` param wins, otherwise the client's +configured network/chain applies. + +## Parameters + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
+ `client` + + `DataClient` + + A client configured with an Alchemy transport +
+ `params` + + [`GetNftMetadataBatchParams`](../type-aliases/GetNftMetadataBatchParams) + + The tokens to look up, cache options, and optional network override +
+ `options?` + + [`RequestOptions`](../type-aliases/RequestOptions) + + Per-request options (abort signal) +
+ +## Returns + +`Promise`\<`object`\[]> + +Metadata for each requested NFT diff --git a/docs/pages/reference/data-apis/src/functions/getNftSales.mdx b/docs/pages/reference/data-apis/src/functions/getNftSales.mdx new file mode 100644 index 0000000000..81783585af --- /dev/null +++ b/docs/pages/reference/data-apis/src/functions/getNftSales.mdx @@ -0,0 +1,101 @@ +--- +title: getNftSales +description: Overview of the getNftSales function +slug: wallets/reference/data-apis/functions/getNftSales +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +function getNftSales( + client, + params, + options?, +): Promise<{ + nftSales?: object[]; + pageKey?: string; + validAt?: { + blockHash?: string; + blockNumber?: number; + blockTimestamp?: string; + }; +}>; +``` + +Defined in: [packages/data-apis/src/actions/nft/getNftSales.ts:21](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/actions/nft/getNftSales.ts#L21) + +Fetches NFT sales matching the given filters. The network is resolved per +request: an explicit `network` param wins, otherwise the client's +configured network/chain applies. + +## Parameters + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
+ `client` + + `DataClient` + + A client configured with an Alchemy transport +
+ `params` + + [`GetNftSalesParams`](../type-aliases/GetNftSalesParams) + + Sale filters, optional network override, and paging options +
+ `options?` + + [`RequestOptions`](../type-aliases/RequestOptions) + + Per-request options (abort signal) +
+ +## Returns + +`Promise`\<\{ +`nftSales?`: `object`\[]; +`pageKey?`: `string`; +`validAt?`: \{ +`blockHash?`: `string`; +`blockNumber?`: `number`; +`blockTimestamp?`: `string`; +}; +}> + +The matching sales and pagination cursor diff --git a/docs/pages/reference/data-apis/src/functions/getNftSalesPages.mdx b/docs/pages/reference/data-apis/src/functions/getNftSalesPages.mdx new file mode 100644 index 0000000000..0c1bb58956 --- /dev/null +++ b/docs/pages/reference/data-apis/src/functions/getNftSalesPages.mdx @@ -0,0 +1,105 @@ +--- +title: getNftSalesPages +description: Overview of the getNftSalesPages function +slug: wallets/reference/data-apis/functions/getNftSalesPages +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +function getNftSalesPages( + client, + params, + options?, +): AsyncGenerator< + { + nftSales?: object[]; + pageKey?: string; + validAt?: { + blockHash?: string; + blockNumber?: number; + blockTimestamp?: string; + }; + }, + void, + undefined +>; +``` + +Defined in: [packages/data-apis/src/actions/nft/getNftSalesPages.ts:16](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/actions/nft/getNftSalesPages.ts#L16) + +Auto-paginating companion to [getNftSales](getNftSales): yields whole pages until the +cursor is exhausted (or `maxPages` is hit), guarding against repeated +cursors. Iterate items with an inner loop over each page. + +## Parameters + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
+ `client` + + `DataClient` + + A client configured with an Alchemy transport +
+ `params` + + [`GetNftSalesParams`](../type-aliases/GetNftSalesParams) + + Same params as getNftSales (the cursor is managed for you) +
+ `options?` + + [`PaginateOptions`](../type-aliases/PaginateOptions) + + Abort signal and page cap +
+ +## Returns + +`AsyncGenerator`\<\{ +`nftSales?`: `object`\[]; +`pageKey?`: `string`; +`validAt?`: \{ +`blockHash?`: `string`; +`blockNumber?`: `number`; +`blockTimestamp?`: `string`; +}; +}, `void`, `undefined`> + +Pages, in order diff --git a/docs/pages/reference/data-apis/src/functions/getNftsByAddress.mdx b/docs/pages/reference/data-apis/src/functions/getNftsByAddress.mdx new file mode 100644 index 0000000000..269a78d285 --- /dev/null +++ b/docs/pages/reference/data-apis/src/functions/getNftsByAddress.mdx @@ -0,0 +1,98 @@ +--- +title: getNftsByAddress +description: Overview of the getNftsByAddress function +slug: wallets/reference/data-apis/functions/getNftsByAddress +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +function getNftsByAddress( + client, + params, + options?, +): Promise<{ + data: { + ownedNfts?: object[]; + pageKey?: string; + totalCount?: number; + }; +}>; +``` + +Defined in: [packages/data-apis/src/actions/portfolio/getNftsByAddress.ts:26](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/actions/portfolio/getNftsByAddress.ts#L26) + +Fetches NFTs for one or more addresses across one or more networks in a +single call. +This is a multi-network request against the global Data API: networks +travel in the request body, so the client's chain is not involved. + +## Parameters + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
+ `client` + + `DataClient` + + A client configured with an Alchemy transport +
+ `params` + + [`GetNftsByAddressParams`](../type-aliases/GetNftsByAddressParams) + + Addresses paired with networks, plus options +
+ `options?` + + [`RequestOptions`](../type-aliases/RequestOptions) + + Per-request options (abort signal) +
+ +## Returns + +`Promise`\<\{ +`data`: \{ +`ownedNfts?`: `object`\[]; +`pageKey?`: `string`; +`totalCount?`: `number`; +}; +}> + +The owned NFTs and pagination cursor diff --git a/docs/pages/reference/data-apis/src/functions/getNftsByAddressPages.mdx b/docs/pages/reference/data-apis/src/functions/getNftsByAddressPages.mdx new file mode 100644 index 0000000000..63df7dd278 --- /dev/null +++ b/docs/pages/reference/data-apis/src/functions/getNftsByAddressPages.mdx @@ -0,0 +1,101 @@ +--- +title: getNftsByAddressPages +description: Overview of the getNftsByAddressPages function +slug: wallets/reference/data-apis/functions/getNftsByAddressPages +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +function getNftsByAddressPages( + client, + params, + options?, +): AsyncGenerator< + { + data: { + ownedNfts?: object[]; + pageKey?: string; + totalCount?: number; + }; + }, + void, + undefined +>; +``` + +Defined in: [packages/data-apis/src/actions/portfolio/getNftsByAddressPages.ts:19](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/actions/portfolio/getNftsByAddressPages.ts#L19) + +Auto-paginating companion to [getNftsByAddress](getNftsByAddress): yields whole pages until the +cursor is exhausted (or `maxPages` is hit), guarding against repeated +cursors. Iterate items with an inner loop over each page. + +## Parameters + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
+ `client` + + `DataClient` + + A client configured with an Alchemy transport +
+ `params` + + [`GetNftsByAddressParams`](../type-aliases/GetNftsByAddressParams) + + Same params as getNftsByAddress (the cursor is managed for you) +
+ `options?` + + [`PaginateOptions`](../type-aliases/PaginateOptions) + + Abort signal and page cap +
+ +## Returns + +`AsyncGenerator`\<\{ +`data`: \{ +`ownedNfts?`: `object`\[]; +`pageKey?`: `string`; +`totalCount?`: `number`; +}; +}, `void`, `undefined`> + +Pages, in order diff --git a/docs/pages/reference/data-apis/src/functions/getNftsForCollection.mdx b/docs/pages/reference/data-apis/src/functions/getNftsForCollection.mdx new file mode 100644 index 0000000000..c859241467 --- /dev/null +++ b/docs/pages/reference/data-apis/src/functions/getNftsForCollection.mdx @@ -0,0 +1,91 @@ +--- +title: getNftsForCollection +description: Overview of the getNftsForCollection function +slug: wallets/reference/data-apis/functions/getNftsForCollection +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +function getNftsForCollection( + client, + params, + options?, +): Promise<{ + nextToken?: string; + nfts?: object[]; +}>; +``` + +Defined in: [packages/data-apis/src/actions/nft/getNftsForCollection.ts:24](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/actions/nft/getNftsForCollection.ts#L24) + +Fetches all NFTs for a given collection (by contract address or collection slug). The network is resolved per +request: an explicit `network` param wins, otherwise the client's +configured network/chain applies. + +## Parameters + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
+ `client` + + `DataClient` + + A client configured with an Alchemy transport +
+ `params` + + [`GetNftsForCollectionParams`](../type-aliases/GetNftsForCollectionParams) + + Collection identifier, optional network override, and paging filters +
+ `options?` + + [`RequestOptions`](../type-aliases/RequestOptions) + + Per-request options (abort signal) +
+ +## Returns + +`Promise`\<\{ +`nextToken?`: `string`; +`nfts?`: `object`\[]; +}> + +The collection's NFTs and next-page token diff --git a/docs/pages/reference/data-apis/src/functions/getNftsForCollectionPages.mdx b/docs/pages/reference/data-apis/src/functions/getNftsForCollectionPages.mdx new file mode 100644 index 0000000000..7e14c9b6c1 --- /dev/null +++ b/docs/pages/reference/data-apis/src/functions/getNftsForCollectionPages.mdx @@ -0,0 +1,95 @@ +--- +title: getNftsForCollectionPages +description: Overview of the getNftsForCollectionPages function +slug: wallets/reference/data-apis/functions/getNftsForCollectionPages +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +function getNftsForCollectionPages( + client, + params, + options?, +): AsyncGenerator< + { + nextToken?: string; + nfts?: object[]; + }, + void, + undefined +>; +``` + +Defined in: [packages/data-apis/src/actions/nft/getNftsForCollectionPages.ts:19](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/actions/nft/getNftsForCollectionPages.ts#L19) + +Auto-paginating companion to [getNftsForCollection](getNftsForCollection): yields whole pages until the +cursor is exhausted (or `maxPages` is hit), guarding against repeated +cursors. Iterate items with an inner loop over each page. + +## Parameters + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
+ `client` + + `DataClient` + + A client configured with an Alchemy transport +
+ `params` + + [`GetNftsForCollectionParams`](../type-aliases/GetNftsForCollectionParams) + + Same params as getNftsForCollection (the cursor is managed for you) +
+ `options?` + + [`PaginateOptions`](../type-aliases/PaginateOptions) + + Abort signal and page cap +
+ +## Returns + +`AsyncGenerator`\<\{ +`nextToken?`: `string`; +`nfts?`: `object`\[]; +}, `void`, `undefined`> + +Pages, in order diff --git a/docs/pages/reference/data-apis/src/functions/getNftsForContract.mdx b/docs/pages/reference/data-apis/src/functions/getNftsForContract.mdx new file mode 100644 index 0000000000..1be96b92ac --- /dev/null +++ b/docs/pages/reference/data-apis/src/functions/getNftsForContract.mdx @@ -0,0 +1,91 @@ +--- +title: getNftsForContract +description: Overview of the getNftsForContract function +slug: wallets/reference/data-apis/functions/getNftsForContract +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +function getNftsForContract( + client, + params, + options?, +): Promise<{ + nfts?: object[]; + pageKey?: string; +}>; +``` + +Defined in: [packages/data-apis/src/actions/nft/getNftsForContract.ts:24](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/actions/nft/getNftsForContract.ts#L24) + +Fetches all NFTs for a given contract. The network is resolved per +request: an explicit `network` param wins, otherwise the client's +configured network/chain applies. + +## Parameters + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
+ `client` + + `DataClient` + + A client configured with an Alchemy transport +
+ `params` + + [`GetNftsForContractParams`](../type-aliases/GetNftsForContractParams) + + Contract address, optional network override, and paging filters +
+ `options?` + + [`RequestOptions`](../type-aliases/RequestOptions) + + Per-request options (abort signal) +
+ +## Returns + +`Promise`\<\{ +`nfts?`: `object`\[]; +`pageKey?`: `string`; +}> + +The contract's NFTs and pagination cursor diff --git a/docs/pages/reference/data-apis/src/functions/getNftsForContractPages.mdx b/docs/pages/reference/data-apis/src/functions/getNftsForContractPages.mdx new file mode 100644 index 0000000000..b701acfdb6 --- /dev/null +++ b/docs/pages/reference/data-apis/src/functions/getNftsForContractPages.mdx @@ -0,0 +1,95 @@ +--- +title: getNftsForContractPages +description: Overview of the getNftsForContractPages function +slug: wallets/reference/data-apis/functions/getNftsForContractPages +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +function getNftsForContractPages( + client, + params, + options?, +): AsyncGenerator< + { + nfts?: object[]; + pageKey?: string; + }, + void, + undefined +>; +``` + +Defined in: [packages/data-apis/src/actions/nft/getNftsForContractPages.ts:19](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/actions/nft/getNftsForContractPages.ts#L19) + +Auto-paginating companion to [getNftsForContract](getNftsForContract): yields whole pages until the +cursor is exhausted (or `maxPages` is hit), guarding against repeated +cursors. Iterate items with an inner loop over each page. + +## Parameters + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
+ `client` + + `DataClient` + + A client configured with an Alchemy transport +
+ `params` + + [`GetNftsForContractParams`](../type-aliases/GetNftsForContractParams) + + Same params as getNftsForContract (the cursor is managed for you) +
+ `options?` + + [`PaginateOptions`](../type-aliases/PaginateOptions) + + Abort signal and page cap +
+ +## Returns + +`AsyncGenerator`\<\{ +`nfts?`: `object`\[]; +`pageKey?`: `string`; +}, `void`, `undefined`> + +Pages, in order diff --git a/docs/pages/reference/data-apis/src/functions/getNftsForOwner.mdx b/docs/pages/reference/data-apis/src/functions/getNftsForOwner.mdx new file mode 100644 index 0000000000..c822eb30c9 --- /dev/null +++ b/docs/pages/reference/data-apis/src/functions/getNftsForOwner.mdx @@ -0,0 +1,103 @@ +--- +title: getNftsForOwner +description: Overview of the getNftsForOwner function +slug: wallets/reference/data-apis/functions/getNftsForOwner +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +function getNftsForOwner( + client, + params, + options?, +): Promise<{ + ownedNfts?: object[]; + pageKey?: string; + totalCount?: number; + validAt?: { + blockHash?: string; + blockNumber?: number; + blockTimestamp?: string; + }; +}>; +``` + +Defined in: [packages/data-apis/src/actions/nft/getNftsForOwner.ts:26](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/actions/nft/getNftsForOwner.ts#L26) + +Fetches NFTs owned by an address on a single network. The network is +resolved per request: an explicit `network` param wins, otherwise the +client's configured network/chain applies. + +## Parameters + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
+ `client` + + `DataClient` + + A client configured with an Alchemy transport +
+ `params` + + [`GetNftsForOwnerParams`](../type-aliases/GetNftsForOwnerParams) + + Owner address, optional network override, and filters +
+ `options?` + + [`RequestOptions`](../type-aliases/RequestOptions) + + Per-request options (abort signal) +
+ +## Returns + +`Promise`\<\{ +`ownedNfts?`: `object`\[]; +`pageKey?`: `string`; +`totalCount?`: `number`; +`validAt?`: \{ +`blockHash?`: `string`; +`blockNumber?`: `number`; +`blockTimestamp?`: `string`; +}; +}> + +The owned NFTs and pagination cursor diff --git a/docs/pages/reference/data-apis/src/functions/getNftsForOwnerPages.mdx b/docs/pages/reference/data-apis/src/functions/getNftsForOwnerPages.mdx new file mode 100644 index 0000000000..6bd3606577 --- /dev/null +++ b/docs/pages/reference/data-apis/src/functions/getNftsForOwnerPages.mdx @@ -0,0 +1,107 @@ +--- +title: getNftsForOwnerPages +description: Overview of the getNftsForOwnerPages function +slug: wallets/reference/data-apis/functions/getNftsForOwnerPages +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +function getNftsForOwnerPages( + client, + params, + options?, +): AsyncGenerator< + { + ownedNfts?: object[]; + pageKey?: string; + totalCount?: number; + validAt?: { + blockHash?: string; + blockNumber?: number; + blockTimestamp?: string; + }; + }, + void, + undefined +>; +``` + +Defined in: [packages/data-apis/src/actions/nft/getNftsForOwnerPages.ts:19](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/actions/nft/getNftsForOwnerPages.ts#L19) + +Auto-paginating companion to [getNftsForOwner](getNftsForOwner): yields whole pages until the +cursor is exhausted (or `maxPages` is hit), guarding against repeated +cursors. Iterate items with an inner loop over each page. + +## Parameters + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
+ `client` + + `DataClient` + + A client configured with an Alchemy transport +
+ `params` + + [`GetNftsForOwnerParams`](../type-aliases/GetNftsForOwnerParams) + + Same params as getNftsForOwner (the cursor is managed for you) +
+ `options?` + + [`PaginateOptions`](../type-aliases/PaginateOptions) + + Abort signal and page cap +
+ +## Returns + +`AsyncGenerator`\<\{ +`ownedNfts?`: `object`\[]; +`pageKey?`: `string`; +`totalCount?`: `number`; +`validAt?`: \{ +`blockHash?`: `string`; +`blockNumber?`: `number`; +`blockTimestamp?`: `string`; +}; +}, `void`, `undefined`> + +Pages, in order diff --git a/docs/pages/reference/data-apis/src/functions/getOwnersForContract.mdx b/docs/pages/reference/data-apis/src/functions/getOwnersForContract.mdx new file mode 100644 index 0000000000..24f2f74946 --- /dev/null +++ b/docs/pages/reference/data-apis/src/functions/getOwnersForContract.mdx @@ -0,0 +1,89 @@ +--- +title: getOwnersForContract +description: Overview of the getOwnersForContract function +slug: wallets/reference/data-apis/functions/getOwnersForContract +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +function getOwnersForContract( + client, + params, + options?, +): Promise<{ + owners?: object[]; +}>; +``` + +Defined in: [packages/data-apis/src/actions/nft/getOwnersForContract.ts:24](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/actions/nft/getOwnersForContract.ts#L24) + +Fetches all owners for an NFT contract. The network is resolved per +request: an explicit `network` param wins, otherwise the client's +configured network/chain applies. + +## Parameters + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
+ `client` + + `DataClient` + + A client configured with an Alchemy transport +
+ `params` + + [`GetOwnersForContractParams`](../type-aliases/GetOwnersForContractParams) + + Contract address, optional network override, and balance options +
+ `options?` + + [`RequestOptions`](../type-aliases/RequestOptions) + + Per-request options (abort signal) +
+ +## Returns + +`Promise`\<\{ +`owners?`: `object`\[]; +}> + +The contract's owners diff --git a/docs/pages/reference/data-apis/src/functions/getOwnersForNft.mdx b/docs/pages/reference/data-apis/src/functions/getOwnersForNft.mdx new file mode 100644 index 0000000000..f0db6e6455 --- /dev/null +++ b/docs/pages/reference/data-apis/src/functions/getOwnersForNft.mdx @@ -0,0 +1,91 @@ +--- +title: getOwnersForNft +description: Overview of the getOwnersForNft function +slug: wallets/reference/data-apis/functions/getOwnersForNft +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +function getOwnersForNft( + client, + params, + options?, +): Promise<{ + owners?: string[]; + pageKey?: string; +}>; +``` + +Defined in: [packages/data-apis/src/actions/nft/getOwnersForNft.ts:24](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/actions/nft/getOwnersForNft.ts#L24) + +Fetches the owners of a specific NFT. The network is resolved per +request: an explicit `network` param wins, otherwise the client's +configured network/chain applies. + +## Parameters + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
+ `client` + + `DataClient` + + A client configured with an Alchemy transport +
+ `params` + + [`GetOwnersForNftParams`](../type-aliases/GetOwnersForNftParams) + + Contract address, token id, and optional network override +
+ `options?` + + [`RequestOptions`](../type-aliases/RequestOptions) + + Per-request options (abort signal) +
+ +## Returns + +`Promise`\<\{ +`owners?`: `string`\[]; +`pageKey?`: `string`; +}> + +The NFT's owners diff --git a/docs/pages/reference/data-apis/src/functions/getSpamContracts.mdx b/docs/pages/reference/data-apis/src/functions/getSpamContracts.mdx new file mode 100644 index 0000000000..aab9b57e9f --- /dev/null +++ b/docs/pages/reference/data-apis/src/functions/getSpamContracts.mdx @@ -0,0 +1,89 @@ +--- +title: getSpamContracts +description: Overview of the getSpamContracts function +slug: wallets/reference/data-apis/functions/getSpamContracts +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +function getSpamContracts( + client, + params?, + options?, +): Promise<{ + contractAddresses?: string[]; +}>; +``` + +Defined in: [packages/data-apis/src/actions/nft/getSpamContracts.ts:24](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/actions/nft/getSpamContracts.ts#L24) + +Fetches the full list of contracts classified as spam on a network. The +network is resolved per request: an explicit `network` param wins, +otherwise the client's configured network/chain applies. + +## Parameters + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
+ `client` + + `DataClient` + + A client configured with an Alchemy transport +
+ `params?` + + [`GetSpamContractsParams`](../type-aliases/GetSpamContractsParams) + + Optional network override +
+ `options?` + + [`RequestOptions`](../type-aliases/RequestOptions) + + Per-request options (abort signal) +
+ +## Returns + +`Promise`\<\{ +`contractAddresses?`: `string`\[]; +}> + +The spam contract addresses diff --git a/docs/pages/reference/data-apis/src/functions/getTokenAllowance.mdx b/docs/pages/reference/data-apis/src/functions/getTokenAllowance.mdx new file mode 100644 index 0000000000..10ce833065 --- /dev/null +++ b/docs/pages/reference/data-apis/src/functions/getTokenAllowance.mdx @@ -0,0 +1,68 @@ +--- +title: getTokenAllowance +description: Overview of the getTokenAllowance function +slug: wallets/reference/data-apis/functions/getTokenAllowance +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +function getTokenAllowance(client, params): Promise; +``` + +Defined in: [packages/data-apis/src/actions/token/getTokenAllowance.ts:21](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/actions/token/getTokenAllowance.ts#L21) + +Fetches the ERC-20 allowance a spender has from an owner via the +`alchemy_getTokenAllowance` JSON-RPC method. Without a `network` override +this uses the client's transport; with one, a transport instance is derived +for the override network. + +## Parameters + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
+ `client` + + `DataClient` + + A client configured with an Alchemy transport +
+ `params` + + [`GetTokenAllowanceParams`](../type-aliases/GetTokenAllowanceParams) + + Contract, owner, spender, and optional network override +
+ +## Returns + +`Promise`\<`string`> + +The allowance as a decimal string diff --git a/docs/pages/reference/data-apis/src/functions/getTokenBalances.mdx b/docs/pages/reference/data-apis/src/functions/getTokenBalances.mdx new file mode 100644 index 0000000000..56c890a6d7 --- /dev/null +++ b/docs/pages/reference/data-apis/src/functions/getTokenBalances.mdx @@ -0,0 +1,71 @@ +--- +title: getTokenBalances +description: Overview of the getTokenBalances function +slug: wallets/reference/data-apis/functions/getTokenBalances +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +function getTokenBalances( + client, + params, +): Promise; +``` + +Defined in: [packages/data-apis/src/actions/token/getTokenBalances.ts:22](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/actions/token/getTokenBalances.ts#L22) + +Fetches ERC-20 (and native) token balances for an address via the +`alchemy_getTokenBalances` JSON-RPC method. Without a `network` override +this uses the client's transport; with one, a transport instance is derived +for the override network. + +## Parameters + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
+ `client` + + `DataClient` + + A client configured with an Alchemy transport +
+ `params` + + [`GetTokenBalancesParams`](../type-aliases/GetTokenBalancesParams) + + Address, token spec, paging options, and optional network override +
+ +## Returns + +`Promise`\<`AlchemyGetTokenBalancesResult`> + +The token balances diff --git a/docs/pages/reference/data-apis/src/functions/getTokenBalancesByAddress.mdx b/docs/pages/reference/data-apis/src/functions/getTokenBalancesByAddress.mdx new file mode 100644 index 0000000000..a8b5168dbe --- /dev/null +++ b/docs/pages/reference/data-apis/src/functions/getTokenBalancesByAddress.mdx @@ -0,0 +1,96 @@ +--- +title: getTokenBalancesByAddress +description: Overview of the getTokenBalancesByAddress function +slug: wallets/reference/data-apis/functions/getTokenBalancesByAddress +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +function getTokenBalancesByAddress( + client, + params, + options?, +): Promise<{ + data: { + pageKey?: string; + tokens?: object[]; + }; +}>; +``` + +Defined in: [packages/data-apis/src/actions/portfolio/getTokenBalancesByAddress.ts:26](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/actions/portfolio/getTokenBalancesByAddress.ts#L26) + +Fetches token balances (without metadata or prices) for one or more +addresses across one or more networks in a single call. +This is a multi-network request against the global Data API: networks +travel in the request body, so the client's chain is not involved. + +## Parameters + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
+ `client` + + `DataClient` + + A client configured with an Alchemy transport +
+ `params` + + [`GetTokenBalancesByAddressParams`](../type-aliases/GetTokenBalancesByAddressParams) + + Addresses paired with networks, plus options +
+ `options?` + + [`RequestOptions`](../type-aliases/RequestOptions) + + Per-request options (abort signal) +
+ +## Returns + +`Promise`\<\{ +`data`: \{ +`pageKey?`: `string`; +`tokens?`: `object`\[]; +}; +}> + +Token balances per wallet/network pair diff --git a/docs/pages/reference/data-apis/src/functions/getTokenMetadata.mdx b/docs/pages/reference/data-apis/src/functions/getTokenMetadata.mdx new file mode 100644 index 0000000000..f414681d29 --- /dev/null +++ b/docs/pages/reference/data-apis/src/functions/getTokenMetadata.mdx @@ -0,0 +1,71 @@ +--- +title: getTokenMetadata +description: Overview of the getTokenMetadata function +slug: wallets/reference/data-apis/functions/getTokenMetadata +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +function getTokenMetadata( + client, + params, +): Promise; +``` + +Defined in: [packages/data-apis/src/actions/token/getTokenMetadata.ts:21](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/actions/token/getTokenMetadata.ts#L21) + +Fetches metadata (name, symbol, decimals, logo) for a token contract via +the `alchemy_getTokenMetadata` JSON-RPC method. Without a `network` +override this uses the client's transport; with one, a transport instance +is derived for the override network. + +## Parameters + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
+ `client` + + `DataClient` + + A client configured with an Alchemy transport +
+ `params` + + [`GetTokenMetadataParams`](../type-aliases/GetTokenMetadataParams) + + The contract address and optional network override +
+ +## Returns + +`Promise`\<`AlchemyGetTokenMetadataResult`> + +The token metadata diff --git a/docs/pages/reference/data-apis/src/functions/getTokenPricesByAddress.mdx b/docs/pages/reference/data-apis/src/functions/getTokenPricesByAddress.mdx new file mode 100644 index 0000000000..c8d9277e2b --- /dev/null +++ b/docs/pages/reference/data-apis/src/functions/getTokenPricesByAddress.mdx @@ -0,0 +1,89 @@ +--- +title: getTokenPricesByAddress +description: Overview of the getTokenPricesByAddress function +slug: wallets/reference/data-apis/functions/getTokenPricesByAddress +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +function getTokenPricesByAddress( + client, + params, + options?, +): Promise<{ + data: object[]; +}>; +``` + +Defined in: [packages/data-apis/src/actions/prices/getTokenPricesByAddress.ts:24](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/actions/prices/getTokenPricesByAddress.ts#L24) + +Fetches current prices for tokens by contract address (max 25 pairs). This +is a multi-network request against the global Prices API: each entry pairs +an address with its network, so the client's chain is not involved. + +## Parameters + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
+ `client` + + `DataClient` + + A client configured with an Alchemy transport +
+ `params` + + [`GetTokenPricesByAddressParams`](../type-aliases/GetTokenPricesByAddressParams) + + Address/network pairs to price +
+ `options?` + + [`RequestOptions`](../type-aliases/RequestOptions) + + Per-request options (abort signal) +
+ +## Returns + +`Promise`\<\{ +`data`: `object`\[]; +}> + +Prices per address/network pair diff --git a/docs/pages/reference/data-apis/src/functions/getTokenPricesBySymbol.mdx b/docs/pages/reference/data-apis/src/functions/getTokenPricesBySymbol.mdx new file mode 100644 index 0000000000..5c2d5b3799 --- /dev/null +++ b/docs/pages/reference/data-apis/src/functions/getTokenPricesBySymbol.mdx @@ -0,0 +1,105 @@ +--- +title: getTokenPricesBySymbol +description: Overview of the getTokenPricesBySymbol function +slug: wallets/reference/data-apis/functions/getTokenPricesBySymbol +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +function getTokenPricesBySymbol( + client, + params, + options?, +): Promise<{ + data: object[]; +}>; +``` + +Defined in: [packages/data-apis/src/actions/prices/getTokenPricesBySymbol.ts:23](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/actions/prices/getTokenPricesBySymbol.ts#L23) + +Fetches current prices for tokens by symbol (max 25). This is a +chain-agnostic request against the global Prices API — no network is +involved at all. + +## Parameters + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
+ `client` + + `DataClient` + + A client configured with an Alchemy transport +
+ `params` + + \{ `symbols`: `string`\[]; } + + The token symbols to price +
+ `params.symbols` + + `string`\[] + + **Description** + + Array of token symbols (limit 25). Example: symbols=\[ETH,BTC] +
+ `options?` + + [`RequestOptions`](../type-aliases/RequestOptions) + + Per-request options (abort signal) +
+ +## Returns + +`Promise`\<\{ +`data`: `object`\[]; +}> + +Prices per symbol diff --git a/docs/pages/reference/data-apis/src/functions/getTokensByAddress.mdx b/docs/pages/reference/data-apis/src/functions/getTokensByAddress.mdx new file mode 100644 index 0000000000..226e0d9116 --- /dev/null +++ b/docs/pages/reference/data-apis/src/functions/getTokensByAddress.mdx @@ -0,0 +1,108 @@ +--- +title: getTokensByAddress +description: Overview of the getTokensByAddress function +slug: wallets/reference/data-apis/functions/getTokensByAddress +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +function getTokensByAddress( + client, + params, + options?, +): Promise<{ + data: { + pageKey?: string; + tokens?: object[]; + }; +}>; +``` + +Defined in: [packages/data-apis/src/actions/portfolio/getTokensByAddress.ts:34](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/actions/portfolio/getTokensByAddress.ts#L34) + +Fetches tokens (with optional metadata and prices) for one or more addresses +across one or more networks in a single call. This is a multi-network +request against the global Data API: networks travel in the request body, +so the client's chain is not involved. + +## Example + +```ts +import { mainnet, base } from "viem/chains"; + +const tokens = await getTokensByAddress(client, { + addresses: [ + { address: "0x...", networks: [mainnet, base, "solana-mainnet"] }, + ], +}); +``` + +## Parameters + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
+ `client` + + `DataClient` + + A client configured with an Alchemy transport +
+ `params` + + [`GetTokensByAddressParams`](../type-aliases/GetTokensByAddressParams) + + Addresses paired with networks, plus options +
+ `options?` + + [`RequestOptions`](../type-aliases/RequestOptions) + + Per-request options (abort signal) +
+ +## Returns + +`Promise`\<\{ +`data`: \{ +`pageKey?`: `string`; +`tokens?`: `object`\[]; +}; +}> + +Token balances, metadata, and prices diff --git a/docs/pages/reference/data-apis/src/functions/isAirdropNft.mdx b/docs/pages/reference/data-apis/src/functions/isAirdropNft.mdx new file mode 100644 index 0000000000..b643d71a8b --- /dev/null +++ b/docs/pages/reference/data-apis/src/functions/isAirdropNft.mdx @@ -0,0 +1,89 @@ +--- +title: isAirdropNft +description: Overview of the isAirdropNft function +slug: wallets/reference/data-apis/functions/isAirdropNft +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +function isAirdropNft( + client, + params, + options?, +): Promise<{ + isAirdrop?: boolean; +}>; +``` + +Defined in: [packages/data-apis/src/actions/nft/isAirdropNft.ts:21](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/actions/nft/isAirdropNft.ts#L21) + +Checks whether an NFT was airdropped to its owner. The network is resolved per +request: an explicit `network` param wins, otherwise the client's +configured network/chain applies. + +## Parameters + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
+ `client` + + `DataClient` + + A client configured with an Alchemy transport +
+ `params` + + [`IsAirdropNftParams`](../type-aliases/IsAirdropNftParams) + + Contract address, token id, and optional network override +
+ `options?` + + [`RequestOptions`](../type-aliases/RequestOptions) + + Per-request options (abort signal) +
+ +## Returns + +`Promise`\<\{ +`isAirdrop?`: `boolean`; +}> + +The airdrop classification diff --git a/docs/pages/reference/data-apis/src/functions/isHolderOfContract.mdx b/docs/pages/reference/data-apis/src/functions/isHolderOfContract.mdx new file mode 100644 index 0000000000..81a54f6e6a --- /dev/null +++ b/docs/pages/reference/data-apis/src/functions/isHolderOfContract.mdx @@ -0,0 +1,89 @@ +--- +title: isHolderOfContract +description: Overview of the isHolderOfContract function +slug: wallets/reference/data-apis/functions/isHolderOfContract +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +function isHolderOfContract( + client, + params, + options?, +): Promise<{ + isHolderOfContract?: boolean; +}>; +``` + +Defined in: [packages/data-apis/src/actions/nft/isHolderOfContract.ts:24](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/actions/nft/isHolderOfContract.ts#L24) + +Checks whether a wallet holds any NFT from a contract. The network is resolved per +request: an explicit `network` param wins, otherwise the client's +configured network/chain applies. + +## Parameters + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
+ `client` + + `DataClient` + + A client configured with an Alchemy transport +
+ `params` + + [`IsHolderOfContractParams`](../type-aliases/IsHolderOfContractParams) + + Wallet address, contract address, and optional network override +
+ `options?` + + [`RequestOptions`](../type-aliases/RequestOptions) + + Per-request options (abort signal) +
+ +## Returns + +`Promise`\<\{ +`isHolderOfContract?`: `boolean`; +}> + +The holder check result diff --git a/docs/pages/reference/data-apis/src/functions/isSpamContract.mdx b/docs/pages/reference/data-apis/src/functions/isSpamContract.mdx new file mode 100644 index 0000000000..b380593102 --- /dev/null +++ b/docs/pages/reference/data-apis/src/functions/isSpamContract.mdx @@ -0,0 +1,89 @@ +--- +title: isSpamContract +description: Overview of the isSpamContract function +slug: wallets/reference/data-apis/functions/isSpamContract +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +function isSpamContract( + client, + params, + options?, +): Promise<{ + isSpamContract?: boolean; +}>; +``` + +Defined in: [packages/data-apis/src/actions/nft/isSpamContract.ts:24](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/actions/nft/isSpamContract.ts#L24) + +Checks whether a contract is classified as spam. The network is resolved per +request: an explicit `network` param wins, otherwise the client's +configured network/chain applies. + +## Parameters + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
+ `client` + + `DataClient` + + A client configured with an Alchemy transport +
+ `params` + + [`IsSpamContractParams`](../type-aliases/IsSpamContractParams) + + Contract address and optional network override +
+ `options?` + + [`RequestOptions`](../type-aliases/RequestOptions) + + Per-request options (abort signal) +
+ +## Returns + +`Promise`\<\{ +`isSpamContract?`: `boolean`; +}> + +The spam classification diff --git a/docs/pages/reference/data-apis/src/functions/searchContractMetadata.mdx b/docs/pages/reference/data-apis/src/functions/searchContractMetadata.mdx new file mode 100644 index 0000000000..366b015b8b --- /dev/null +++ b/docs/pages/reference/data-apis/src/functions/searchContractMetadata.mdx @@ -0,0 +1,81 @@ +--- +title: searchContractMetadata +description: Overview of the searchContractMetadata function +slug: wallets/reference/data-apis/functions/searchContractMetadata +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +function searchContractMetadata(client, params, options?): Promise; +``` + +Defined in: [packages/data-apis/src/actions/nft/searchContractMetadata.ts:24](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/actions/nft/searchContractMetadata.ts#L24) + +Searches NFT contract metadata by keyword. The network is resolved per +request: an explicit `network` param wins, otherwise the client's +configured network/chain applies. + +## Parameters + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
+ `client` + + `DataClient` + + A client configured with an Alchemy transport +
+ `params` + + [`SearchContractMetadataParams`](../type-aliases/SearchContractMetadataParams) + + Search query and optional network override +
+ `options?` + + [`RequestOptions`](../type-aliases/RequestOptions) + + Per-request options (abort signal) +
+ +## Returns + +`Promise`\<`object`\[]> + +The matching contracts diff --git a/docs/pages/reference/data-apis/src/functions/summarizeNftAttributes.mdx b/docs/pages/reference/data-apis/src/functions/summarizeNftAttributes.mdx new file mode 100644 index 0000000000..dd146caa3f --- /dev/null +++ b/docs/pages/reference/data-apis/src/functions/summarizeNftAttributes.mdx @@ -0,0 +1,93 @@ +--- +title: summarizeNftAttributes +description: Overview of the summarizeNftAttributes function +slug: wallets/reference/data-apis/functions/summarizeNftAttributes +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +function summarizeNftAttributes( + client, + params, + options?, +): Promise<{ + contractAddress: string; + summary?: Record; + totalSupply?: string; +}>; +``` + +Defined in: [packages/data-apis/src/actions/nft/summarizeNftAttributes.ts:24](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/actions/nft/summarizeNftAttributes.ts#L24) + +Summarizes attribute prevalence for an NFT contract. The network is resolved per +request: an explicit `network` param wins, otherwise the client's +configured network/chain applies. + +## Parameters + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeDescription
+ `client` + + `DataClient` + + A client configured with an Alchemy transport +
+ `params` + + [`SummarizeNftAttributesParams`](../type-aliases/SummarizeNftAttributesParams) + + Contract address and optional network override +
+ `options?` + + [`RequestOptions`](../type-aliases/RequestOptions) + + Per-request options (abort signal) +
+ +## Returns + +`Promise`\<\{ +`contractAddress`: `string`; +`summary?`: `Record`\<`string`, `never`>; +`totalSupply?`: `string`; +}> + +The attribute summary diff --git a/docs/pages/reference/data-apis/src/interfaces/PortfolioAddressEntry.mdx b/docs/pages/reference/data-apis/src/interfaces/PortfolioAddressEntry.mdx new file mode 100644 index 0000000000..6fb5e366d5 --- /dev/null +++ b/docs/pages/reference/data-apis/src/interfaces/PortfolioAddressEntry.mdx @@ -0,0 +1,55 @@ +--- +title: PortfolioAddressEntry +description: An address paired with the networks to query it on. +slug: wallets/reference/data-apis/interfaces/PortfolioAddressEntry +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +Defined in: [packages/data-apis/src/types.ts:103](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L103) + +An address paired with the networks to query it on. + +## Properties + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PropertyTypeDescription
+ `address` + + `string` + + ‐ +
+ `networks` + + `NetworkInput`\[] + + Networks to query; accepts viem Chains, Alchemy slugs, or CAIP-2 ids. +
diff --git a/docs/pages/reference/data-apis/src/interfaces/PriceAddressEntry.mdx b/docs/pages/reference/data-apis/src/interfaces/PriceAddressEntry.mdx new file mode 100644 index 0000000000..12ac07a82d --- /dev/null +++ b/docs/pages/reference/data-apis/src/interfaces/PriceAddressEntry.mdx @@ -0,0 +1,55 @@ +--- +title: PriceAddressEntry +description: A token address paired with the network it lives on. +slug: wallets/reference/data-apis/interfaces/PriceAddressEntry +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +Defined in: [packages/data-apis/src/types.ts:152](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L152) + +A token address paired with the network it lives on. + +## Properties + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PropertyTypeDescription
+ `address` + + `string` + + ‐ +
+ `network` + + `NetworkInput` + + Accepts a viem Chain, an Alchemy slug, or a CAIP-2 id. +
diff --git a/docs/pages/reference/data-apis/src/type-aliases/AlchemyDataClient.mdx b/docs/pages/reference/data-apis/src/type-aliases/AlchemyDataClient.mdx new file mode 100644 index 0000000000..33421c4134 --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/AlchemyDataClient.mdx @@ -0,0 +1,15 @@ +--- +title: AlchemyDataClient +description: Overview of AlchemyDataClient +slug: wallets/reference/data-apis/type-aliases/AlchemyDataClient +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type AlchemyDataClient = Client & + DataActions; +``` + +Defined in: [packages/data-apis/src/client.ts:25](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/client.ts#L25) diff --git a/docs/pages/reference/data-apis/src/type-aliases/AlchemyDataClientOptions.mdx b/docs/pages/reference/data-apis/src/type-aliases/AlchemyDataClientOptions.mdx new file mode 100644 index 0000000000..3ae36fac92 --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/AlchemyDataClientOptions.mdx @@ -0,0 +1,50 @@ +--- +title: AlchemyDataClientOptions +description: Overview of AlchemyDataClientOptions +slug: wallets/reference/data-apis/type-aliases/AlchemyDataClientOptions +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type AlchemyDataClientOptions = Pick< + AlchemyTransportConfig, + "apiKey" | "jwt" | "url" | "fetchOptions" +> & + object; +``` + +Defined in: [packages/data-apis/src/client.ts:12](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/client.ts#L12) + +## Type Declaration + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
+ `network?` + + `NetworkInput` + + Default network for network-scoped calls (NFT, Token, Transfers). + Accepts a viem Chain, an Alchemy slug ("eth-mainnet"), or CAIP-2 + ("eip155:1"). Multi-network calls (Portfolio) take explicit networks + per request. +
diff --git a/docs/pages/reference/data-apis/src/type-aliases/AssetTransfer.mdx b/docs/pages/reference/data-apis/src/type-aliases/AssetTransfer.mdx new file mode 100644 index 0000000000..b24b798e1d --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/AssetTransfer.mdx @@ -0,0 +1,14 @@ +--- +title: AssetTransfer +description: Overview of AssetTransfer +slug: wallets/reference/data-apis/type-aliases/AssetTransfer +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type AssetTransfer = NonNullable[number]; +``` + +Defined in: [packages/data-apis/src/types.ts:297](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L297) diff --git a/docs/pages/reference/data-apis/src/type-aliases/ComputeRarityParams.mdx b/docs/pages/reference/data-apis/src/type-aliases/ComputeRarityParams.mdx new file mode 100644 index 0000000000..efbb3a05ac --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/ComputeRarityParams.mdx @@ -0,0 +1,14 @@ +--- +title: ComputeRarityParams +description: Overview of ComputeRarityParams +slug: wallets/reference/data-apis/type-aliases/ComputeRarityParams +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type ComputeRarityParams = NetworkScoped; +``` + +Defined in: [packages/data-apis/src/types.ts:244](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L244) diff --git a/docs/pages/reference/data-apis/src/type-aliases/ComputeRarityResult.mdx b/docs/pages/reference/data-apis/src/type-aliases/ComputeRarityResult.mdx new file mode 100644 index 0000000000..1707675e81 --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/ComputeRarityResult.mdx @@ -0,0 +1,14 @@ +--- +title: ComputeRarityResult +description: Overview of ComputeRarityResult +slug: wallets/reference/data-apis/type-aliases/ComputeRarityResult +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type ComputeRarityResult = ComputeRarityResponse; +``` + +Defined in: [packages/data-apis/src/types.ts:245](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L245) diff --git a/docs/pages/reference/data-apis/src/type-aliases/DataActions.mdx b/docs/pages/reference/data-apis/src/type-aliases/DataActions.mdx new file mode 100644 index 0000000000..2575659a81 --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/DataActions.mdx @@ -0,0 +1,490 @@ +--- +title: DataActions +description: The namespaced Data API actions attached by the dataActions decorator. +slug: wallets/reference/data-apis/type-aliases/DataActions +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type DataActions = object; +``` + +Defined in: [packages/data-apis/src/decorator.ts:64](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/decorator.ts#L64) + +The namespaced Data API actions attached by the [dataActions](../functions/dataActions) decorator. + +## Properties + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PropertyType
+ `nft` + + `object` +
+ `nft.computeRarity` + + `Action`\<[`ComputeRarityParams`](ComputeRarityParams), [`ComputeRarityResult`](ComputeRarityResult)> +
+ `nft.getCollectionMetadata` + + `Action`\<[`GetCollectionMetadataParams`](GetCollectionMetadataParams), [`GetCollectionMetadataResult`](GetCollectionMetadataResult)> +
+ `nft.getCollectionsForOwner` + + `Action`\<[`GetCollectionsForOwnerParams`](GetCollectionsForOwnerParams), [`GetCollectionsForOwnerResult`](GetCollectionsForOwnerResult)> +
+ `nft.getCollectionsForOwnerPages` + + `PagesAction`\<[`GetCollectionsForOwnerParams`](GetCollectionsForOwnerParams), [`GetCollectionsForOwnerResult`](GetCollectionsForOwnerResult)> +
+ `nft.getContractMetadata` + + `Action`\<[`GetContractMetadataParams`](GetContractMetadataParams), [`GetContractMetadataResult`](GetContractMetadataResult)> +
+ `nft.getContractMetadataBatch` + + `Action`\<[`GetContractMetadataBatchParams`](GetContractMetadataBatchParams), `any`\[]> +
+ `nft.getContractsForOwner` + + `Action`\<[`GetContractsForOwnerParams`](GetContractsForOwnerParams), [`GetContractsForOwnerResult`](GetContractsForOwnerResult)> +
+ `nft.getContractsForOwnerPages` + + `PagesAction`\<[`GetContractsForOwnerParams`](GetContractsForOwnerParams), [`GetContractsForOwnerResult`](GetContractsForOwnerResult)> +
+ `nft.getFloorPrice` + + `Action`\<[`GetFloorPriceParams`](GetFloorPriceParams), [`GetFloorPriceResult`](GetFloorPriceResult)> +
+ `nft.getNftMetadata` + + `Action`\<[`GetNftMetadataParams`](GetNftMetadataParams), [`GetNftMetadataResult`](GetNftMetadataResult)> +
+ `nft.getNftMetadataBatch` + + `Action`\<[`GetNftMetadataBatchParams`](GetNftMetadataBatchParams), `any`\[]> +
+ `nft.getNftSales` + + `Action`\<[`GetNftSalesParams`](GetNftSalesParams), [`GetNftSalesResult`](GetNftSalesResult)> +
+ `nft.getNftSalesPages` + + `PagesAction`\<[`GetNftSalesParams`](GetNftSalesParams), [`GetNftSalesResult`](GetNftSalesResult)> +
+ `nft.getNftsForCollection` + + `Action`\<[`GetNftsForCollectionParams`](GetNftsForCollectionParams), [`GetNftsForCollectionResult`](GetNftsForCollectionResult)> +
+ `nft.getNftsForCollectionPages` + + `PagesAction`\<[`GetNftsForCollectionParams`](GetNftsForCollectionParams), [`GetNftsForCollectionResult`](GetNftsForCollectionResult)> +
+ `nft.getNftsForContract` + + `Action`\<[`GetNftsForContractParams`](GetNftsForContractParams), [`GetNftsForContractResult`](GetNftsForContractResult)> +
+ `nft.getNftsForContractPages` + + `PagesAction`\<[`GetNftsForContractParams`](GetNftsForContractParams), [`GetNftsForContractResult`](GetNftsForContractResult)> +
+ `nft.getNftsForOwner` + + `Action`\<[`GetNftsForOwnerParams`](GetNftsForOwnerParams), [`GetNftsForOwnerResult`](GetNftsForOwnerResult)> +
+ `nft.getNftsForOwnerPages` + + `PagesAction`\<[`GetNftsForOwnerParams`](GetNftsForOwnerParams), [`GetNftsForOwnerResult`](GetNftsForOwnerResult)> +
+ `nft.getOwnersForContract` + + `Action`\<[`GetOwnersForContractParams`](GetOwnersForContractParams), [`GetOwnersForContractResult`](GetOwnersForContractResult)> +
+ `nft.getOwnersForNft` + + `Action`\<[`GetOwnersForNftParams`](GetOwnersForNftParams), [`GetOwnersForNftResult`](GetOwnersForNftResult)> +
+ `nft.getSpamContracts` + + `Action`\<[`GetSpamContractsParams`](GetSpamContractsParams), [`GetSpamContractsResult`](GetSpamContractsResult)> +
+ `nft.isAirdropNft` + + `Action`\<[`IsAirdropNftParams`](IsAirdropNftParams), [`IsAirdropNftResult`](IsAirdropNftResult)> +
+ `nft.isHolderOfContract` + + `Action`\<[`IsHolderOfContractParams`](IsHolderOfContractParams), [`IsHolderOfContractResult`](IsHolderOfContractResult)> +
+ `nft.isSpamContract` + + `Action`\<[`IsSpamContractParams`](IsSpamContractParams), [`IsSpamContractResult`](IsSpamContractResult)> +
+ `nft.searchContractMetadata` + + `Action`\<[`SearchContractMetadataParams`](SearchContractMetadataParams), `any`\[]> +
+ `nft.summarizeNftAttributes` + + `Action`\<[`SummarizeNftAttributesParams`](SummarizeNftAttributesParams), [`SummarizeNftAttributesResult`](SummarizeNftAttributesResult)> +
+ `portfolio` + + `object` +
+ `portfolio.getNftContractsByAddress` + + `Action`\<[`GetNftContractsByAddressParams`](GetNftContractsByAddressParams), [`GetNftContractsByAddressResult`](GetNftContractsByAddressResult)> +
+ `portfolio.getNftContractsByAddressPages` + + `PagesAction`\<[`GetNftContractsByAddressParams`](GetNftContractsByAddressParams), [`GetNftContractsByAddressResult`](GetNftContractsByAddressResult)> +
+ `portfolio.getNftsByAddress` + + `Action`\<[`GetNftsByAddressParams`](GetNftsByAddressParams), [`GetNftsByAddressResult`](GetNftsByAddressResult)> +
+ `portfolio.getNftsByAddressPages` + + `PagesAction`\<[`GetNftsByAddressParams`](GetNftsByAddressParams), [`GetNftsByAddressResult`](GetNftsByAddressResult)> +
+ `portfolio.getTokenBalancesByAddress` + + `Action`\<[`GetTokenBalancesByAddressParams`](GetTokenBalancesByAddressParams), [`GetTokenBalancesByAddressResult`](GetTokenBalancesByAddressResult)> +
+ `portfolio.getTokensByAddress` + + `Action`\<[`GetTokensByAddressParams`](GetTokensByAddressParams), [`GetTokensByAddressResult`](GetTokensByAddressResult)> +
+ `prices` + + `object` +
+ `prices.getHistoricalTokenPrices` + + `Action`\<[`GetHistoricalTokenPricesParams`](GetHistoricalTokenPricesParams), [`GetHistoricalTokenPricesResult`](GetHistoricalTokenPricesResult)> +
+ `prices.getTokenPricesByAddress` + + `Action`\<[`GetTokenPricesByAddressParams`](GetTokenPricesByAddressParams), [`GetTokenPricesByAddressResult`](GetTokenPricesByAddressResult)> +
+ `prices.getTokenPricesBySymbol` + + `Action`\<[`GetTokenPricesBySymbolParams`](GetTokenPricesBySymbolParams), [`GetTokenPricesBySymbolResult`](GetTokenPricesBySymbolResult)> +
+ `token` + + `object` +
+ `token.getTokenAllowance` + + `RpcAction`\<[`GetTokenAllowanceParams`](GetTokenAllowanceParams), [`GetTokenAllowanceResult`](GetTokenAllowanceResult)> +
+ `token.getTokenBalances` + + `RpcAction`\<[`GetTokenBalancesParams`](GetTokenBalancesParams), [`GetTokenBalancesResult`](GetTokenBalancesResult)> +
+ `token.getTokenMetadata` + + `RpcAction`\<[`GetTokenMetadataParams`](GetTokenMetadataParams), [`GetTokenMetadataResult`](GetTokenMetadataResult)> +
+ `transfers` + + `object` +
+ `transfers.getAssetTransfers` + + `RpcAction`\<[`GetAssetTransfersParams`](GetAssetTransfersParams), [`GetAssetTransfersResult`](GetAssetTransfersResult)> +
+ `transfers.getAssetTransfersPages` + + `PagesAction`\<[`GetAssetTransfersParams`](GetAssetTransfersParams), [`GetAssetTransfersResult`](GetAssetTransfersResult)> +
diff --git a/docs/pages/reference/data-apis/src/type-aliases/DataRpcSchema.mdx b/docs/pages/reference/data-apis/src/type-aliases/DataRpcSchema.mdx new file mode 100644 index 0000000000..0b9e08ac59 --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/DataRpcSchema.mdx @@ -0,0 +1,28 @@ +--- +title: DataRpcSchema +description: 'viem RpcSchema entries for the Data JSON-RPC methods. Attach to a client to get typed `client.request({ method: "alchemy_getAssetTransfers", ... })`. The transfers ReturnType uses the SDK''s GetAssetTransfersResult, which collapses the spec''s "Not Found (null)" string branch (a docs-spec artifact).' +slug: wallets/reference/data-apis/type-aliases/DataRpcSchema +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type DataRpcSchema = [ + { + Method: TransfersRpcSchema[0]["Method"]; + Parameters: TransfersRpcSchema[0]["Parameters"]; + ReturnType: GetAssetTransfersResult; + }, + ...TokenRpcSchema, +]; +``` + +Defined in: [packages/data-apis/src/schema/rpc.ts:21](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/schema/rpc.ts#L21) + +viem RpcSchema entries for the Data JSON-RPC methods. Attach to a client to +get typed `client.request({ method: "alchemy_getAssetTransfers", ... })`. + +The transfers ReturnType uses the SDK's [GetAssetTransfersResult](GetAssetTransfersResult), +which collapses the spec's "Not Found (null)" string branch (a docs-spec +artifact). diff --git a/docs/pages/reference/data-apis/src/type-aliases/GetAssetTransfersParams.mdx b/docs/pages/reference/data-apis/src/type-aliases/GetAssetTransfersParams.mdx new file mode 100644 index 0000000000..4adef767a7 --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/GetAssetTransfersParams.mdx @@ -0,0 +1,45 @@ +--- +title: GetAssetTransfersParams +description: Generated RPC params plus the SDK's network override. +slug: wallets/reference/data-apis/type-aliases/GetAssetTransfersParams +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type GetAssetTransfersParams = AlchemyGetAssetTransfersParams & object; +``` + +Defined in: [packages/data-apis/src/types.ts:282](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L282) + +Generated RPC params plus the SDK's network override. + +## Type Declaration + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
+ `network?` + + `NetworkInput` + + Overrides the client-level network for this request. +
diff --git a/docs/pages/reference/data-apis/src/type-aliases/GetAssetTransfersResult.mdx b/docs/pages/reference/data-apis/src/type-aliases/GetAssetTransfersResult.mdx new file mode 100644 index 0000000000..67f80d4898 --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/GetAssetTransfersResult.mdx @@ -0,0 +1,18 @@ +--- +title: GetAssetTransfersResult +description: 'The spec result is `oneOf: ["Not Found (null)" string, object]`; the string branch is a docs-spec artifact the SDK deliberately does not surface, so it is collapsed away here (and in DataRpcSchema).' +slug: wallets/reference/data-apis/type-aliases/GetAssetTransfersResult +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type GetAssetTransfersResult = Exclude; +``` + +Defined in: [packages/data-apis/src/types.ts:292](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L292) + +The spec result is `oneOf: ["Not Found (null)" string, object]`; the string +branch is a docs-spec artifact the SDK deliberately does not surface, so it +is collapsed away here (and in [DataRpcSchema](DataRpcSchema)). diff --git a/docs/pages/reference/data-apis/src/type-aliases/GetCollectionMetadataParams.mdx b/docs/pages/reference/data-apis/src/type-aliases/GetCollectionMetadataParams.mdx new file mode 100644 index 0000000000..d8dbf166e6 --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/GetCollectionMetadataParams.mdx @@ -0,0 +1,14 @@ +--- +title: GetCollectionMetadataParams +description: Overview of GetCollectionMetadataParams +slug: wallets/reference/data-apis/type-aliases/GetCollectionMetadataParams +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type GetCollectionMetadataParams = NetworkScoped; +``` + +Defined in: [packages/data-apis/src/types.ts:200](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L200) diff --git a/docs/pages/reference/data-apis/src/type-aliases/GetCollectionMetadataResult.mdx b/docs/pages/reference/data-apis/src/type-aliases/GetCollectionMetadataResult.mdx new file mode 100644 index 0000000000..824a54d012 --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/GetCollectionMetadataResult.mdx @@ -0,0 +1,14 @@ +--- +title: GetCollectionMetadataResult +description: Overview of GetCollectionMetadataResult +slug: wallets/reference/data-apis/type-aliases/GetCollectionMetadataResult +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type GetCollectionMetadataResult = GetCollectionMetadataResponse; +``` + +Defined in: [packages/data-apis/src/types.ts:202](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L202) diff --git a/docs/pages/reference/data-apis/src/type-aliases/GetCollectionsForOwnerParams.mdx b/docs/pages/reference/data-apis/src/type-aliases/GetCollectionsForOwnerParams.mdx new file mode 100644 index 0000000000..3c83c0796b --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/GetCollectionsForOwnerParams.mdx @@ -0,0 +1,14 @@ +--- +title: GetCollectionsForOwnerParams +description: Overview of GetCollectionsForOwnerParams +slug: wallets/reference/data-apis/type-aliases/GetCollectionsForOwnerParams +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type GetCollectionsForOwnerParams = NetworkScoped; +``` + +Defined in: [packages/data-apis/src/types.ts:208](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L208) diff --git a/docs/pages/reference/data-apis/src/type-aliases/GetCollectionsForOwnerResult.mdx b/docs/pages/reference/data-apis/src/type-aliases/GetCollectionsForOwnerResult.mdx new file mode 100644 index 0000000000..365f3380f4 --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/GetCollectionsForOwnerResult.mdx @@ -0,0 +1,14 @@ +--- +title: GetCollectionsForOwnerResult +description: Overview of GetCollectionsForOwnerResult +slug: wallets/reference/data-apis/type-aliases/GetCollectionsForOwnerResult +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type GetCollectionsForOwnerResult = GetCollectionsForOwnerResponse; +``` + +Defined in: [packages/data-apis/src/types.ts:210](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L210) diff --git a/docs/pages/reference/data-apis/src/type-aliases/GetContractMetadataBatchParams.mdx b/docs/pages/reference/data-apis/src/type-aliases/GetContractMetadataBatchParams.mdx new file mode 100644 index 0000000000..102e4c55d7 --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/GetContractMetadataBatchParams.mdx @@ -0,0 +1,43 @@ +--- +title: GetContractMetadataBatchParams +description: Overview of GetContractMetadataBatchParams +slug: wallets/reference/data-apis/type-aliases/GetContractMetadataBatchParams +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type GetContractMetadataBatchParams = GetContractMetadataBatchBody & object; +``` + +Defined in: [packages/data-apis/src/types.ts:194](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L194) + +## Type Declaration + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
+ `network?` + + `NetworkInput` + + Overrides the client-level network for this request. +
diff --git a/docs/pages/reference/data-apis/src/type-aliases/GetContractMetadataBatchResult.mdx b/docs/pages/reference/data-apis/src/type-aliases/GetContractMetadataBatchResult.mdx new file mode 100644 index 0000000000..cee96390d3 --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/GetContractMetadataBatchResult.mdx @@ -0,0 +1,14 @@ +--- +title: GetContractMetadataBatchResult +description: Overview of GetContractMetadataBatchResult +slug: wallets/reference/data-apis/type-aliases/GetContractMetadataBatchResult +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type GetContractMetadataBatchResult = any[]; +``` + +Defined in: [packages/data-apis/src/types.ts:198](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L198) diff --git a/docs/pages/reference/data-apis/src/type-aliases/GetContractMetadataParams.mdx b/docs/pages/reference/data-apis/src/type-aliases/GetContractMetadataParams.mdx new file mode 100644 index 0000000000..9b35b87eda --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/GetContractMetadataParams.mdx @@ -0,0 +1,14 @@ +--- +title: GetContractMetadataParams +description: Overview of GetContractMetadataParams +slug: wallets/reference/data-apis/type-aliases/GetContractMetadataParams +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type GetContractMetadataParams = NetworkScoped; +``` + +Defined in: [packages/data-apis/src/types.ts:191](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L191) diff --git a/docs/pages/reference/data-apis/src/type-aliases/GetContractMetadataResult.mdx b/docs/pages/reference/data-apis/src/type-aliases/GetContractMetadataResult.mdx new file mode 100644 index 0000000000..67d65acb42 --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/GetContractMetadataResult.mdx @@ -0,0 +1,14 @@ +--- +title: GetContractMetadataResult +description: Overview of GetContractMetadataResult +slug: wallets/reference/data-apis/type-aliases/GetContractMetadataResult +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type GetContractMetadataResult = GetContractMetadataResponse; +``` + +Defined in: [packages/data-apis/src/types.ts:192](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L192) diff --git a/docs/pages/reference/data-apis/src/type-aliases/GetContractsForOwnerParams.mdx b/docs/pages/reference/data-apis/src/type-aliases/GetContractsForOwnerParams.mdx new file mode 100644 index 0000000000..24497ba16a --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/GetContractsForOwnerParams.mdx @@ -0,0 +1,14 @@ +--- +title: GetContractsForOwnerParams +description: Overview of GetContractsForOwnerParams +slug: wallets/reference/data-apis/type-aliases/GetContractsForOwnerParams +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type GetContractsForOwnerParams = NetworkScoped; +``` + +Defined in: [packages/data-apis/src/types.ts:204](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L204) diff --git a/docs/pages/reference/data-apis/src/type-aliases/GetContractsForOwnerResult.mdx b/docs/pages/reference/data-apis/src/type-aliases/GetContractsForOwnerResult.mdx new file mode 100644 index 0000000000..b3e50636c5 --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/GetContractsForOwnerResult.mdx @@ -0,0 +1,14 @@ +--- +title: GetContractsForOwnerResult +description: Overview of GetContractsForOwnerResult +slug: wallets/reference/data-apis/type-aliases/GetContractsForOwnerResult +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type GetContractsForOwnerResult = GetContractsForOwnerResponse; +``` + +Defined in: [packages/data-apis/src/types.ts:206](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L206) diff --git a/docs/pages/reference/data-apis/src/type-aliases/GetFloorPriceParams.mdx b/docs/pages/reference/data-apis/src/type-aliases/GetFloorPriceParams.mdx new file mode 100644 index 0000000000..4aa9340839 --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/GetFloorPriceParams.mdx @@ -0,0 +1,14 @@ +--- +title: GetFloorPriceParams +description: Overview of GetFloorPriceParams +slug: wallets/reference/data-apis/type-aliases/GetFloorPriceParams +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type GetFloorPriceParams = NetworkScoped; +``` + +Defined in: [packages/data-apis/src/types.ts:222](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L222) diff --git a/docs/pages/reference/data-apis/src/type-aliases/GetFloorPriceResult.mdx b/docs/pages/reference/data-apis/src/type-aliases/GetFloorPriceResult.mdx new file mode 100644 index 0000000000..ed0baef02f --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/GetFloorPriceResult.mdx @@ -0,0 +1,14 @@ +--- +title: GetFloorPriceResult +description: Overview of GetFloorPriceResult +slug: wallets/reference/data-apis/type-aliases/GetFloorPriceResult +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type GetFloorPriceResult = GetFloorPriceResponse; +``` + +Defined in: [packages/data-apis/src/types.ts:223](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L223) diff --git a/docs/pages/reference/data-apis/src/type-aliases/GetHistoricalTokenPricesParams.mdx b/docs/pages/reference/data-apis/src/type-aliases/GetHistoricalTokenPricesParams.mdx new file mode 100644 index 0000000000..f0b4b5cf45 --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/GetHistoricalTokenPricesParams.mdx @@ -0,0 +1,15 @@ +--- +title: GetHistoricalTokenPricesParams +description: Overview of GetHistoricalTokenPricesParams +slug: wallets/reference/data-apis/type-aliases/GetHistoricalTokenPricesParams +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type GetHistoricalTokenPricesParams = + WithNetworkInput; +``` + +Defined in: [packages/data-apis/src/types.ts:166](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L166) diff --git a/docs/pages/reference/data-apis/src/type-aliases/GetHistoricalTokenPricesResult.mdx b/docs/pages/reference/data-apis/src/type-aliases/GetHistoricalTokenPricesResult.mdx new file mode 100644 index 0000000000..d868effe1c --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/GetHistoricalTokenPricesResult.mdx @@ -0,0 +1,14 @@ +--- +title: GetHistoricalTokenPricesResult +description: Overview of GetHistoricalTokenPricesResult +slug: wallets/reference/data-apis/type-aliases/GetHistoricalTokenPricesResult +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type GetHistoricalTokenPricesResult = GetHistoricalTokenPricesResponse; +``` + +Defined in: [packages/data-apis/src/types.ts:168](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L168) diff --git a/docs/pages/reference/data-apis/src/type-aliases/GetNftContractsByAddressParams.mdx b/docs/pages/reference/data-apis/src/type-aliases/GetNftContractsByAddressParams.mdx new file mode 100644 index 0000000000..c04c503e87 --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/GetNftContractsByAddressParams.mdx @@ -0,0 +1,15 @@ +--- +title: GetNftContractsByAddressParams +description: Overview of GetNftContractsByAddressParams +slug: wallets/reference/data-apis/type-aliases/GetNftContractsByAddressParams +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type GetNftContractsByAddressParams = + PortfolioParams; +``` + +Defined in: [packages/data-apis/src/types.ts:141](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L141) diff --git a/docs/pages/reference/data-apis/src/type-aliases/GetNftContractsByAddressResult.mdx b/docs/pages/reference/data-apis/src/type-aliases/GetNftContractsByAddressResult.mdx new file mode 100644 index 0000000000..e988b1a438 --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/GetNftContractsByAddressResult.mdx @@ -0,0 +1,14 @@ +--- +title: GetNftContractsByAddressResult +description: Overview of GetNftContractsByAddressResult +slug: wallets/reference/data-apis/type-aliases/GetNftContractsByAddressResult +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type GetNftContractsByAddressResult = GetNftContractsByAddressResponse; +``` + +Defined in: [packages/data-apis/src/types.ts:143](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L143) diff --git a/docs/pages/reference/data-apis/src/type-aliases/GetNftMetadataBatchParams.mdx b/docs/pages/reference/data-apis/src/type-aliases/GetNftMetadataBatchParams.mdx new file mode 100644 index 0000000000..ee0e595eb9 --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/GetNftMetadataBatchParams.mdx @@ -0,0 +1,43 @@ +--- +title: GetNftMetadataBatchParams +description: Overview of GetNftMetadataBatchParams +slug: wallets/reference/data-apis/type-aliases/GetNftMetadataBatchParams +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type GetNftMetadataBatchParams = GetNftMetadataBatchBody & object; +``` + +Defined in: [packages/data-apis/src/types.ts:185](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L185) + +## Type Declaration + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
+ `network?` + + `NetworkInput` + + Overrides the client-level network for this request. +
diff --git a/docs/pages/reference/data-apis/src/type-aliases/GetNftMetadataBatchResult.mdx b/docs/pages/reference/data-apis/src/type-aliases/GetNftMetadataBatchResult.mdx new file mode 100644 index 0000000000..509180a453 --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/GetNftMetadataBatchResult.mdx @@ -0,0 +1,14 @@ +--- +title: GetNftMetadataBatchResult +description: Overview of GetNftMetadataBatchResult +slug: wallets/reference/data-apis/type-aliases/GetNftMetadataBatchResult +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type GetNftMetadataBatchResult = any[]; +``` + +Defined in: [packages/data-apis/src/types.ts:189](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L189) diff --git a/docs/pages/reference/data-apis/src/type-aliases/GetNftMetadataParams.mdx b/docs/pages/reference/data-apis/src/type-aliases/GetNftMetadataParams.mdx new file mode 100644 index 0000000000..e30aabe9fe --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/GetNftMetadataParams.mdx @@ -0,0 +1,14 @@ +--- +title: GetNftMetadataParams +description: Overview of GetNftMetadataParams +slug: wallets/reference/data-apis/type-aliases/GetNftMetadataParams +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type GetNftMetadataParams = NetworkScoped; +``` + +Defined in: [packages/data-apis/src/types.ts:182](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L182) diff --git a/docs/pages/reference/data-apis/src/type-aliases/GetNftMetadataResult.mdx b/docs/pages/reference/data-apis/src/type-aliases/GetNftMetadataResult.mdx new file mode 100644 index 0000000000..5d50656e60 --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/GetNftMetadataResult.mdx @@ -0,0 +1,14 @@ +--- +title: GetNftMetadataResult +description: Overview of GetNftMetadataResult +slug: wallets/reference/data-apis/type-aliases/GetNftMetadataResult +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type GetNftMetadataResult = GetNftMetadataResponse; +``` + +Defined in: [packages/data-apis/src/types.ts:183](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L183) diff --git a/docs/pages/reference/data-apis/src/type-aliases/GetNftSalesParams.mdx b/docs/pages/reference/data-apis/src/type-aliases/GetNftSalesParams.mdx new file mode 100644 index 0000000000..2569e900e8 --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/GetNftSalesParams.mdx @@ -0,0 +1,14 @@ +--- +title: GetNftSalesParams +description: Overview of GetNftSalesParams +slug: wallets/reference/data-apis/type-aliases/GetNftSalesParams +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type GetNftSalesParams = NetworkScoped; +``` + +Defined in: [packages/data-apis/src/types.ts:219](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L219) diff --git a/docs/pages/reference/data-apis/src/type-aliases/GetNftSalesResult.mdx b/docs/pages/reference/data-apis/src/type-aliases/GetNftSalesResult.mdx new file mode 100644 index 0000000000..2fdf7bf7a3 --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/GetNftSalesResult.mdx @@ -0,0 +1,14 @@ +--- +title: GetNftSalesResult +description: Overview of GetNftSalesResult +slug: wallets/reference/data-apis/type-aliases/GetNftSalesResult +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type GetNftSalesResult = GetNftSalesResponse; +``` + +Defined in: [packages/data-apis/src/types.ts:220](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L220) diff --git a/docs/pages/reference/data-apis/src/type-aliases/GetNftsByAddressParams.mdx b/docs/pages/reference/data-apis/src/type-aliases/GetNftsByAddressParams.mdx new file mode 100644 index 0000000000..47a137f87b --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/GetNftsByAddressParams.mdx @@ -0,0 +1,14 @@ +--- +title: GetNftsByAddressParams +description: Overview of GetNftsByAddressParams +slug: wallets/reference/data-apis/type-aliases/GetNftsByAddressParams +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type GetNftsByAddressParams = PortfolioParams; +``` + +Defined in: [packages/data-apis/src/types.ts:138](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L138) diff --git a/docs/pages/reference/data-apis/src/type-aliases/GetNftsByAddressResult.mdx b/docs/pages/reference/data-apis/src/type-aliases/GetNftsByAddressResult.mdx new file mode 100644 index 0000000000..7979beba13 --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/GetNftsByAddressResult.mdx @@ -0,0 +1,14 @@ +--- +title: GetNftsByAddressResult +description: Overview of GetNftsByAddressResult +slug: wallets/reference/data-apis/type-aliases/GetNftsByAddressResult +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type GetNftsByAddressResult = GetNftsByAddressResponse; +``` + +Defined in: [packages/data-apis/src/types.ts:139](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L139) diff --git a/docs/pages/reference/data-apis/src/type-aliases/GetNftsForCollectionParams.mdx b/docs/pages/reference/data-apis/src/type-aliases/GetNftsForCollectionParams.mdx new file mode 100644 index 0000000000..ffd8d215b9 --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/GetNftsForCollectionParams.mdx @@ -0,0 +1,14 @@ +--- +title: GetNftsForCollectionParams +description: Overview of GetNftsForCollectionParams +slug: wallets/reference/data-apis/type-aliases/GetNftsForCollectionParams +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type GetNftsForCollectionParams = NetworkScoped; +``` + +Defined in: [packages/data-apis/src/types.ts:178](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L178) diff --git a/docs/pages/reference/data-apis/src/type-aliases/GetNftsForCollectionResult.mdx b/docs/pages/reference/data-apis/src/type-aliases/GetNftsForCollectionResult.mdx new file mode 100644 index 0000000000..24f651a906 --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/GetNftsForCollectionResult.mdx @@ -0,0 +1,14 @@ +--- +title: GetNftsForCollectionResult +description: Overview of GetNftsForCollectionResult +slug: wallets/reference/data-apis/type-aliases/GetNftsForCollectionResult +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type GetNftsForCollectionResult = GetNftsForCollectionResponse; +``` + +Defined in: [packages/data-apis/src/types.ts:180](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L180) diff --git a/docs/pages/reference/data-apis/src/type-aliases/GetNftsForContractParams.mdx b/docs/pages/reference/data-apis/src/type-aliases/GetNftsForContractParams.mdx new file mode 100644 index 0000000000..820b670a63 --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/GetNftsForContractParams.mdx @@ -0,0 +1,14 @@ +--- +title: GetNftsForContractParams +description: Overview of GetNftsForContractParams +slug: wallets/reference/data-apis/type-aliases/GetNftsForContractParams +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type GetNftsForContractParams = NetworkScoped; +``` + +Defined in: [packages/data-apis/src/types.ts:175](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L175) diff --git a/docs/pages/reference/data-apis/src/type-aliases/GetNftsForContractResult.mdx b/docs/pages/reference/data-apis/src/type-aliases/GetNftsForContractResult.mdx new file mode 100644 index 0000000000..7109b40278 --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/GetNftsForContractResult.mdx @@ -0,0 +1,14 @@ +--- +title: GetNftsForContractResult +description: Overview of GetNftsForContractResult +slug: wallets/reference/data-apis/type-aliases/GetNftsForContractResult +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type GetNftsForContractResult = GetNftsForContractResponse; +``` + +Defined in: [packages/data-apis/src/types.ts:176](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L176) diff --git a/docs/pages/reference/data-apis/src/type-aliases/GetNftsForOwnerParams.mdx b/docs/pages/reference/data-apis/src/type-aliases/GetNftsForOwnerParams.mdx new file mode 100644 index 0000000000..858929b264 --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/GetNftsForOwnerParams.mdx @@ -0,0 +1,14 @@ +--- +title: GetNftsForOwnerParams +description: Overview of GetNftsForOwnerParams +slug: wallets/reference/data-apis/type-aliases/GetNftsForOwnerParams +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type GetNftsForOwnerParams = NetworkScoped; +``` + +Defined in: [packages/data-apis/src/types.ts:172](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L172) diff --git a/docs/pages/reference/data-apis/src/type-aliases/GetNftsForOwnerResult.mdx b/docs/pages/reference/data-apis/src/type-aliases/GetNftsForOwnerResult.mdx new file mode 100644 index 0000000000..c64bc22f68 --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/GetNftsForOwnerResult.mdx @@ -0,0 +1,14 @@ +--- +title: GetNftsForOwnerResult +description: Overview of GetNftsForOwnerResult +slug: wallets/reference/data-apis/type-aliases/GetNftsForOwnerResult +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type GetNftsForOwnerResult = GetNftsForOwnerResponse; +``` + +Defined in: [packages/data-apis/src/types.ts:173](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L173) diff --git a/docs/pages/reference/data-apis/src/type-aliases/GetOwnersForContractParams.mdx b/docs/pages/reference/data-apis/src/type-aliases/GetOwnersForContractParams.mdx new file mode 100644 index 0000000000..9f5eb3107f --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/GetOwnersForContractParams.mdx @@ -0,0 +1,14 @@ +--- +title: GetOwnersForContractParams +description: Overview of GetOwnersForContractParams +slug: wallets/reference/data-apis/type-aliases/GetOwnersForContractParams +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type GetOwnersForContractParams = NetworkScoped; +``` + +Defined in: [packages/data-apis/src/types.ts:215](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L215) diff --git a/docs/pages/reference/data-apis/src/type-aliases/GetOwnersForContractResult.mdx b/docs/pages/reference/data-apis/src/type-aliases/GetOwnersForContractResult.mdx new file mode 100644 index 0000000000..906bc149c4 --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/GetOwnersForContractResult.mdx @@ -0,0 +1,14 @@ +--- +title: GetOwnersForContractResult +description: Overview of GetOwnersForContractResult +slug: wallets/reference/data-apis/type-aliases/GetOwnersForContractResult +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type GetOwnersForContractResult = GetOwnersForContractResponse; +``` + +Defined in: [packages/data-apis/src/types.ts:217](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L217) diff --git a/docs/pages/reference/data-apis/src/type-aliases/GetOwnersForNftParams.mdx b/docs/pages/reference/data-apis/src/type-aliases/GetOwnersForNftParams.mdx new file mode 100644 index 0000000000..55127ea63d --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/GetOwnersForNftParams.mdx @@ -0,0 +1,14 @@ +--- +title: GetOwnersForNftParams +description: Overview of GetOwnersForNftParams +slug: wallets/reference/data-apis/type-aliases/GetOwnersForNftParams +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type GetOwnersForNftParams = NetworkScoped; +``` + +Defined in: [packages/data-apis/src/types.ts:212](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L212) diff --git a/docs/pages/reference/data-apis/src/type-aliases/GetOwnersForNftResult.mdx b/docs/pages/reference/data-apis/src/type-aliases/GetOwnersForNftResult.mdx new file mode 100644 index 0000000000..94b6aecc51 --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/GetOwnersForNftResult.mdx @@ -0,0 +1,14 @@ +--- +title: GetOwnersForNftResult +description: Overview of GetOwnersForNftResult +slug: wallets/reference/data-apis/type-aliases/GetOwnersForNftResult +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type GetOwnersForNftResult = GetOwnersForNftResponse; +``` + +Defined in: [packages/data-apis/src/types.ts:213](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L213) diff --git a/docs/pages/reference/data-apis/src/type-aliases/GetSpamContractsParams.mdx b/docs/pages/reference/data-apis/src/type-aliases/GetSpamContractsParams.mdx new file mode 100644 index 0000000000..8bbc8aef0b --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/GetSpamContractsParams.mdx @@ -0,0 +1,43 @@ +--- +title: GetSpamContractsParams +description: Overview of GetSpamContractsParams +slug: wallets/reference/data-apis/type-aliases/GetSpamContractsParams +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type GetSpamContractsParams = object; +``` + +Defined in: [packages/data-apis/src/types.ts:229](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L229) + +## Properties + + + + + + + + + + + + + + + + + + + + +
PropertyTypeDescription
+ `network?` + + `NetworkInput` + + Overrides the client-level network for this request. +
diff --git a/docs/pages/reference/data-apis/src/type-aliases/GetSpamContractsResult.mdx b/docs/pages/reference/data-apis/src/type-aliases/GetSpamContractsResult.mdx new file mode 100644 index 0000000000..f80bd26e71 --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/GetSpamContractsResult.mdx @@ -0,0 +1,14 @@ +--- +title: GetSpamContractsResult +description: Overview of GetSpamContractsResult +slug: wallets/reference/data-apis/type-aliases/GetSpamContractsResult +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type GetSpamContractsResult = GetSpamContractsResponse; +``` + +Defined in: [packages/data-apis/src/types.ts:233](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L233) diff --git a/docs/pages/reference/data-apis/src/type-aliases/GetTokenAllowanceParams.mdx b/docs/pages/reference/data-apis/src/type-aliases/GetTokenAllowanceParams.mdx new file mode 100644 index 0000000000..f664a3d457 --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/GetTokenAllowanceParams.mdx @@ -0,0 +1,43 @@ +--- +title: GetTokenAllowanceParams +description: Overview of GetTokenAllowanceParams +slug: wallets/reference/data-apis/type-aliases/GetTokenAllowanceParams +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type GetTokenAllowanceParams = AlchemyGetTokenAllowanceParams & object; +``` + +Defined in: [packages/data-apis/src/types.ts:273](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L273) + +## Type Declaration + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
+ `network?` + + `NetworkInput` + + Overrides the client-level network for this request. +
diff --git a/docs/pages/reference/data-apis/src/type-aliases/GetTokenAllowanceResult.mdx b/docs/pages/reference/data-apis/src/type-aliases/GetTokenAllowanceResult.mdx new file mode 100644 index 0000000000..3d86752095 --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/GetTokenAllowanceResult.mdx @@ -0,0 +1,14 @@ +--- +title: GetTokenAllowanceResult +description: Overview of GetTokenAllowanceResult +slug: wallets/reference/data-apis/type-aliases/GetTokenAllowanceResult +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type GetTokenAllowanceResult = AlchemyGetTokenAllowanceResult; +``` + +Defined in: [packages/data-apis/src/types.ts:277](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L277) diff --git a/docs/pages/reference/data-apis/src/type-aliases/GetTokenBalancesByAddressParams.mdx b/docs/pages/reference/data-apis/src/type-aliases/GetTokenBalancesByAddressParams.mdx new file mode 100644 index 0000000000..1c5a006791 --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/GetTokenBalancesByAddressParams.mdx @@ -0,0 +1,15 @@ +--- +title: GetTokenBalancesByAddressParams +description: Overview of GetTokenBalancesByAddressParams +slug: wallets/reference/data-apis/type-aliases/GetTokenBalancesByAddressParams +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type GetTokenBalancesByAddressParams = + PortfolioParams; +``` + +Defined in: [packages/data-apis/src/types.ts:134](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L134) diff --git a/docs/pages/reference/data-apis/src/type-aliases/GetTokenBalancesByAddressResult.mdx b/docs/pages/reference/data-apis/src/type-aliases/GetTokenBalancesByAddressResult.mdx new file mode 100644 index 0000000000..b1ec86bb47 --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/GetTokenBalancesByAddressResult.mdx @@ -0,0 +1,14 @@ +--- +title: GetTokenBalancesByAddressResult +description: Overview of GetTokenBalancesByAddressResult +slug: wallets/reference/data-apis/type-aliases/GetTokenBalancesByAddressResult +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type GetTokenBalancesByAddressResult = GetTokenBalancesByAddressResponse; +``` + +Defined in: [packages/data-apis/src/types.ts:136](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L136) diff --git a/docs/pages/reference/data-apis/src/type-aliases/GetTokenBalancesParams.mdx b/docs/pages/reference/data-apis/src/type-aliases/GetTokenBalancesParams.mdx new file mode 100644 index 0000000000..97e04e5efc --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/GetTokenBalancesParams.mdx @@ -0,0 +1,85 @@ +--- +title: GetTokenBalancesParams +description: Overview of GetTokenBalancesParams +slug: wallets/reference/data-apis/type-aliases/GetTokenBalancesParams +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type GetTokenBalancesParams = object; +``` + +Defined in: [packages/data-apis/src/types.ts:253](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L253) + +## Properties + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PropertyTypeDescription
+ `address` + + `AlchemyGetTokenBalancesAddressParam` + + The address to fetch balances for. +
+ `network?` + + `NetworkInput` + + Overrides the client-level network for this request. +
+ `options?` + + `AlchemyGetTokenBalancesOptionsParam` + + Paging options (pageKey/maxCount; only valid with the "erc20" spec). +
+ `tokenSpec?` + + `AlchemyGetTokenBalancesTokenSpecParam` + + "erc20" | "NATIVE\_TOKEN" | "DEFAULT\_TOKENS" or an explicit contract list. +
diff --git a/docs/pages/reference/data-apis/src/type-aliases/GetTokenBalancesResult.mdx b/docs/pages/reference/data-apis/src/type-aliases/GetTokenBalancesResult.mdx new file mode 100644 index 0000000000..ff233c79ca --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/GetTokenBalancesResult.mdx @@ -0,0 +1,14 @@ +--- +title: GetTokenBalancesResult +description: Overview of GetTokenBalancesResult +slug: wallets/reference/data-apis/type-aliases/GetTokenBalancesResult +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type GetTokenBalancesResult = AlchemyGetTokenBalancesResult; +``` + +Defined in: [packages/data-apis/src/types.ts:263](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L263) diff --git a/docs/pages/reference/data-apis/src/type-aliases/GetTokenMetadataParams.mdx b/docs/pages/reference/data-apis/src/type-aliases/GetTokenMetadataParams.mdx new file mode 100644 index 0000000000..6a8f2ef68f --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/GetTokenMetadataParams.mdx @@ -0,0 +1,57 @@ +--- +title: GetTokenMetadataParams +description: Overview of GetTokenMetadataParams +slug: wallets/reference/data-apis/type-aliases/GetTokenMetadataParams +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type GetTokenMetadataParams = object; +``` + +Defined in: [packages/data-apis/src/types.ts:265](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L265) + +## Properties + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PropertyTypeDescription
+ `contractAddress` + + `AlchemyGetTokenMetadataParams` + + The token contract address. +
+ `network?` + + `NetworkInput` + + Overrides the client-level network for this request. +
diff --git a/docs/pages/reference/data-apis/src/type-aliases/GetTokenMetadataResult.mdx b/docs/pages/reference/data-apis/src/type-aliases/GetTokenMetadataResult.mdx new file mode 100644 index 0000000000..6f5eb8e600 --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/GetTokenMetadataResult.mdx @@ -0,0 +1,14 @@ +--- +title: GetTokenMetadataResult +description: Overview of GetTokenMetadataResult +slug: wallets/reference/data-apis/type-aliases/GetTokenMetadataResult +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type GetTokenMetadataResult = AlchemyGetTokenMetadataResult; +``` + +Defined in: [packages/data-apis/src/types.ts:271](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L271) diff --git a/docs/pages/reference/data-apis/src/type-aliases/GetTokenPricesByAddressParams.mdx b/docs/pages/reference/data-apis/src/type-aliases/GetTokenPricesByAddressParams.mdx new file mode 100644 index 0000000000..8da2057662 --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/GetTokenPricesByAddressParams.mdx @@ -0,0 +1,42 @@ +--- +title: GetTokenPricesByAddressParams +description: Overview of GetTokenPricesByAddressParams +slug: wallets/reference/data-apis/type-aliases/GetTokenPricesByAddressParams +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type GetTokenPricesByAddressParams = Omit< + GetTokenPricesByAddressBody, + "addresses" +> & + object; +``` + +Defined in: [packages/data-apis/src/types.ts:158](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L158) + +## Type Declaration + + + + + + + + + + + + + + + + + +
NameType
+ `addresses` + + [`PriceAddressEntry`](../interfaces/PriceAddressEntry)\[] +
diff --git a/docs/pages/reference/data-apis/src/type-aliases/GetTokenPricesByAddressResult.mdx b/docs/pages/reference/data-apis/src/type-aliases/GetTokenPricesByAddressResult.mdx new file mode 100644 index 0000000000..c1a5b8f7a0 --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/GetTokenPricesByAddressResult.mdx @@ -0,0 +1,14 @@ +--- +title: GetTokenPricesByAddressResult +description: Overview of GetTokenPricesByAddressResult +slug: wallets/reference/data-apis/type-aliases/GetTokenPricesByAddressResult +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type GetTokenPricesByAddressResult = GetTokenPricesByAddressResponse; +``` + +Defined in: [packages/data-apis/src/types.ts:164](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L164) diff --git a/docs/pages/reference/data-apis/src/type-aliases/GetTokenPricesBySymbolParams.mdx b/docs/pages/reference/data-apis/src/type-aliases/GetTokenPricesBySymbolParams.mdx new file mode 100644 index 0000000000..a4340e24fb --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/GetTokenPricesBySymbolParams.mdx @@ -0,0 +1,16 @@ +--- +title: GetTokenPricesBySymbolParams +description: "Chain-agnostic: token symbols only, no network involved." +slug: wallets/reference/data-apis/type-aliases/GetTokenPricesBySymbolParams +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type GetTokenPricesBySymbolParams = GetTokenPricesBySymbolQuery; +``` + +Defined in: [packages/data-apis/src/types.ts:148](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L148) + +Chain-agnostic: token symbols only, no network involved. diff --git a/docs/pages/reference/data-apis/src/type-aliases/GetTokenPricesBySymbolResult.mdx b/docs/pages/reference/data-apis/src/type-aliases/GetTokenPricesBySymbolResult.mdx new file mode 100644 index 0000000000..314f543ba0 --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/GetTokenPricesBySymbolResult.mdx @@ -0,0 +1,14 @@ +--- +title: GetTokenPricesBySymbolResult +description: Overview of GetTokenPricesBySymbolResult +slug: wallets/reference/data-apis/type-aliases/GetTokenPricesBySymbolResult +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type GetTokenPricesBySymbolResult = GetTokenPricesBySymbolResponse; +``` + +Defined in: [packages/data-apis/src/types.ts:149](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L149) diff --git a/docs/pages/reference/data-apis/src/type-aliases/GetTokensByAddressParams.mdx b/docs/pages/reference/data-apis/src/type-aliases/GetTokensByAddressParams.mdx new file mode 100644 index 0000000000..d33a42a825 --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/GetTokensByAddressParams.mdx @@ -0,0 +1,14 @@ +--- +title: GetTokensByAddressParams +description: Overview of GetTokensByAddressParams +slug: wallets/reference/data-apis/type-aliases/GetTokensByAddressParams +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type GetTokensByAddressParams = PortfolioParams; +``` + +Defined in: [packages/data-apis/src/types.ts:128](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L128) diff --git a/docs/pages/reference/data-apis/src/type-aliases/GetTokensByAddressResult.mdx b/docs/pages/reference/data-apis/src/type-aliases/GetTokensByAddressResult.mdx new file mode 100644 index 0000000000..af2758041b --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/GetTokensByAddressResult.mdx @@ -0,0 +1,14 @@ +--- +title: GetTokensByAddressResult +description: Overview of GetTokensByAddressResult +slug: wallets/reference/data-apis/type-aliases/GetTokensByAddressResult +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type GetTokensByAddressResult = GetTokensByAddressResponse; +``` + +Defined in: [packages/data-apis/src/types.ts:129](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L129) diff --git a/docs/pages/reference/data-apis/src/type-aliases/IsAirdropNftParams.mdx b/docs/pages/reference/data-apis/src/type-aliases/IsAirdropNftParams.mdx new file mode 100644 index 0000000000..4d4d0773ff --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/IsAirdropNftParams.mdx @@ -0,0 +1,14 @@ +--- +title: IsAirdropNftParams +description: Overview of IsAirdropNftParams +slug: wallets/reference/data-apis/type-aliases/IsAirdropNftParams +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type IsAirdropNftParams = NetworkScoped; +``` + +Defined in: [packages/data-apis/src/types.ts:238](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L238) diff --git a/docs/pages/reference/data-apis/src/type-aliases/IsAirdropNftResult.mdx b/docs/pages/reference/data-apis/src/type-aliases/IsAirdropNftResult.mdx new file mode 100644 index 0000000000..39de5788f4 --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/IsAirdropNftResult.mdx @@ -0,0 +1,14 @@ +--- +title: IsAirdropNftResult +description: Overview of IsAirdropNftResult +slug: wallets/reference/data-apis/type-aliases/IsAirdropNftResult +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type IsAirdropNftResult = IsAirdropNftResponse; +``` + +Defined in: [packages/data-apis/src/types.ts:239](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L239) diff --git a/docs/pages/reference/data-apis/src/type-aliases/IsHolderOfContractParams.mdx b/docs/pages/reference/data-apis/src/type-aliases/IsHolderOfContractParams.mdx new file mode 100644 index 0000000000..fb4a00261d --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/IsHolderOfContractParams.mdx @@ -0,0 +1,14 @@ +--- +title: IsHolderOfContractParams +description: Overview of IsHolderOfContractParams +slug: wallets/reference/data-apis/type-aliases/IsHolderOfContractParams +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type IsHolderOfContractParams = NetworkScoped; +``` + +Defined in: [packages/data-apis/src/types.ts:241](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L241) diff --git a/docs/pages/reference/data-apis/src/type-aliases/IsHolderOfContractResult.mdx b/docs/pages/reference/data-apis/src/type-aliases/IsHolderOfContractResult.mdx new file mode 100644 index 0000000000..a6b797270f --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/IsHolderOfContractResult.mdx @@ -0,0 +1,14 @@ +--- +title: IsHolderOfContractResult +description: Overview of IsHolderOfContractResult +slug: wallets/reference/data-apis/type-aliases/IsHolderOfContractResult +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type IsHolderOfContractResult = IsHolderOfContractResponse; +``` + +Defined in: [packages/data-apis/src/types.ts:242](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L242) diff --git a/docs/pages/reference/data-apis/src/type-aliases/IsSpamContractParams.mdx b/docs/pages/reference/data-apis/src/type-aliases/IsSpamContractParams.mdx new file mode 100644 index 0000000000..1d24a34285 --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/IsSpamContractParams.mdx @@ -0,0 +1,14 @@ +--- +title: IsSpamContractParams +description: Overview of IsSpamContractParams +slug: wallets/reference/data-apis/type-aliases/IsSpamContractParams +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type IsSpamContractParams = NetworkScoped; +``` + +Defined in: [packages/data-apis/src/types.ts:235](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L235) diff --git a/docs/pages/reference/data-apis/src/type-aliases/IsSpamContractResult.mdx b/docs/pages/reference/data-apis/src/type-aliases/IsSpamContractResult.mdx new file mode 100644 index 0000000000..1bb482d015 --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/IsSpamContractResult.mdx @@ -0,0 +1,14 @@ +--- +title: IsSpamContractResult +description: Overview of IsSpamContractResult +slug: wallets/reference/data-apis/type-aliases/IsSpamContractResult +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type IsSpamContractResult = IsSpamContractResponse; +``` + +Defined in: [packages/data-apis/src/types.ts:236](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L236) diff --git a/docs/pages/reference/data-apis/src/type-aliases/NftRestSchema.mdx b/docs/pages/reference/data-apis/src/type-aliases/NftRestSchema.mdx new file mode 100644 index 0000000000..08f80b75d3 --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/NftRestSchema.mdx @@ -0,0 +1,164 @@ +--- +title: NftRestSchema +description: RestRequestSchema entries for the nft REST API. +slug: wallets/reference/data-apis/type-aliases/NftRestSchema +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type NftRestSchema = readonly [ + { + Body?: undefined; + Method: "GET"; + Query: GetNftsForOwnerQuery; + Response: GetNftsForOwnerResponse; + Route: "getNFTsForOwner"; + }, + { + Body?: undefined; + Method: "GET"; + Query: GetNftsForContractQuery; + Response: GetNftsForContractResponse; + Route: "getNFTsForContract"; + }, + { + Body?: undefined; + Method: "GET"; + Query?: GetNftsForCollectionQuery; + Response: GetNftsForCollectionResponse; + Route: "getNFTsForCollection"; + }, + { + Body?: undefined; + Method: "GET"; + Query: GetNftMetadataQuery; + Response: GetNftMetadataResponse; + Route: "getNFTMetadata"; + }, + { + Body: GetNftMetadataBatchBody; + Method: "POST"; + Query?: undefined; + Response: any[]; + Route: "getNFTMetadataBatch"; + }, + { + Body?: undefined; + Method: "GET"; + Query: GetContractMetadataQuery; + Response: GetContractMetadataResponse; + Route: "getContractMetadata"; + }, + { + Body: GetContractMetadataBatchBody; + Method: "POST"; + Query?: undefined; + Response: any[]; + Route: "getContractMetadataBatch"; + }, + { + Body?: undefined; + Method: "GET"; + Query: GetCollectionMetadataQuery; + Response: GetCollectionMetadataResponse; + Route: "getCollectionMetadata"; + }, + { + Body?: undefined; + Method: "GET"; + Query: GetContractsForOwnerQuery; + Response: GetContractsForOwnerResponse; + Route: "getContractsForOwner"; + }, + { + Body?: undefined; + Method: "GET"; + Query: GetCollectionsForOwnerQuery; + Response: GetCollectionsForOwnerResponse; + Route: "getCollectionsForOwner"; + }, + { + Body?: undefined; + Method: "GET"; + Query: GetOwnersForNftQuery; + Response: GetOwnersForNftResponse; + Route: "getOwnersForNFT"; + }, + { + Body?: undefined; + Method: "GET"; + Query: GetOwnersForContractQuery; + Response: GetOwnersForContractResponse; + Route: "getOwnersForContract"; + }, + { + Body?: undefined; + Method: "GET"; + Query?: GetNftSalesQuery; + Response: GetNftSalesResponse; + Route: "getNFTSales"; + }, + { + Body?: undefined; + Method: "GET"; + Query: GetFloorPriceQuery; + Response: GetFloorPriceResponse; + Route: "getFloorPrice"; + }, + { + Body?: undefined; + Method: "GET"; + Query: SearchContractMetadataQuery; + Response: any[]; + Route: "searchContractMetadata"; + }, + { + Body?: undefined; + Method: "GET"; + Query?: undefined; + Response: GetSpamContractsResponse; + Route: "getSpamContracts"; + }, + { + Body?: undefined; + Method: "GET"; + Query: IsSpamContractQuery; + Response: IsSpamContractResponse; + Route: "isSpamContract"; + }, + { + Body?: undefined; + Method: "GET"; + Query: IsAirdropNftQuery; + Response: IsAirdropNftResponse; + Route: "isAirdropNFT"; + }, + { + Body?: undefined; + Method: "GET"; + Query: IsHolderOfContractQuery; + Response: IsHolderOfContractResponse; + Route: "isHolderOfContract"; + }, + { + Body?: undefined; + Method: "GET"; + Query: ComputeRarityQuery; + Response: ComputeRarityResponse; + Route: "computeRarity"; + }, + { + Body?: undefined; + Method: "GET"; + Query: SummarizeNftAttributesQuery; + Response: SummarizeNftAttributesResponse; + Route: "summarizeNFTAttributes"; + }, +]; +``` + +Defined in: [packages/data-apis/src/generated/rest/nft.schema.ts:194](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/generated/rest/nft.schema.ts#L194) + +RestRequestSchema entries for the nft REST API. diff --git a/docs/pages/reference/data-apis/src/type-aliases/PaginateOptions.mdx b/docs/pages/reference/data-apis/src/type-aliases/PaginateOptions.mdx new file mode 100644 index 0000000000..2f2615d7a7 --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/PaginateOptions.mdx @@ -0,0 +1,59 @@ +--- +title: PaginateOptions +description: Options accepted by the `*Pages` async-iterator actions. +slug: wallets/reference/data-apis/type-aliases/PaginateOptions +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type PaginateOptions = object; +``` + +Defined in: [packages/data-apis/src/internal/paginate.ts:4](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/internal/paginate.ts#L4) + +Options accepted by the `*Pages` async-iterator actions. + +## Properties + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PropertyTypeDescription
+ `maxPages?` + + `number` + + Stop after this many pages (the page that hits the cap is still yielded). +
+ `signal?` + + `AbortSignal` + + Aborts iteration (checked between pages and passed to page requests). +
diff --git a/docs/pages/reference/data-apis/src/type-aliases/PortfolioRestSchema.mdx b/docs/pages/reference/data-apis/src/type-aliases/PortfolioRestSchema.mdx new file mode 100644 index 0000000000..b1aff7e126 --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/PortfolioRestSchema.mdx @@ -0,0 +1,45 @@ +--- +title: PortfolioRestSchema +description: RestRequestSchema entries for the portfolio REST API. +slug: wallets/reference/data-apis/type-aliases/PortfolioRestSchema +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type PortfolioRestSchema = readonly [ + { + Body: GetTokensByAddressBody; + Method: "POST"; + Query?: undefined; + Response: GetTokensByAddressResponse; + Route: "assets/tokens/by-address"; + }, + { + Body: GetTokenBalancesByAddressBody; + Method: "POST"; + Query?: undefined; + Response: GetTokenBalancesByAddressResponse; + Route: "assets/tokens/balances/by-address"; + }, + { + Body: GetNftsByAddressBody; + Method: "POST"; + Query?: undefined; + Response: GetNftsByAddressResponse; + Route: "assets/nfts/by-address"; + }, + { + Body: GetNftContractsByAddressBody; + Method: "POST"; + Query?: undefined; + Response: GetNftContractsByAddressResponse; + Route: "assets/nfts/contracts/by-address"; + }, +]; +``` + +Defined in: [packages/data-apis/src/generated/rest/portfolio.schema.ts:46](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/generated/rest/portfolio.schema.ts#L46) + +RestRequestSchema entries for the portfolio REST API. diff --git a/docs/pages/reference/data-apis/src/type-aliases/PortfolioToken.mdx b/docs/pages/reference/data-apis/src/type-aliases/PortfolioToken.mdx new file mode 100644 index 0000000000..68be5b085a --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/PortfolioToken.mdx @@ -0,0 +1,16 @@ +--- +title: PortfolioToken +description: Overview of PortfolioToken +slug: wallets/reference/data-apis/type-aliases/PortfolioToken +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type PortfolioToken = NonNullable< + GetTokensByAddressResponse["data"]["tokens"] +>[number]; +``` + +Defined in: [packages/data-apis/src/types.ts:130](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L130) diff --git a/docs/pages/reference/data-apis/src/type-aliases/PricesRestSchema.mdx b/docs/pages/reference/data-apis/src/type-aliases/PricesRestSchema.mdx new file mode 100644 index 0000000000..8229bff260 --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/PricesRestSchema.mdx @@ -0,0 +1,38 @@ +--- +title: PricesRestSchema +description: RestRequestSchema entries for the prices REST API. +slug: wallets/reference/data-apis/type-aliases/PricesRestSchema +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type PricesRestSchema = readonly [ + { + Body?: undefined; + Method: "GET"; + Query: GetTokenPricesBySymbolQuery; + Response: GetTokenPricesBySymbolResponse; + Route: "tokens/by-symbol"; + }, + { + Body: GetTokenPricesByAddressBody; + Method: "POST"; + Query?: undefined; + Response: GetTokenPricesByAddressResponse; + Route: "tokens/by-address"; + }, + { + Body: GetHistoricalTokenPricesBody; + Method: "POST"; + Query?: undefined; + Response: GetHistoricalTokenPricesResponse; + Route: "tokens/historical"; + }, +]; +``` + +Defined in: [packages/data-apis/src/generated/rest/prices.schema.ts:37](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/generated/rest/prices.schema.ts#L37) + +RestRequestSchema entries for the prices REST API. diff --git a/docs/pages/reference/data-apis/src/type-aliases/RequestOptions.mdx b/docs/pages/reference/data-apis/src/type-aliases/RequestOptions.mdx new file mode 100644 index 0000000000..23f240cbbf --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/RequestOptions.mdx @@ -0,0 +1,45 @@ +--- +title: RequestOptions +description: Per-request options accepted by data actions. +slug: wallets/reference/data-apis/type-aliases/RequestOptions +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type RequestOptions = object; +``` + +Defined in: [packages/data-apis/src/internal/clientHelpers.ts:20](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/internal/clientHelpers.ts#L20) + +Per-request options accepted by data actions. + +## Properties + + + + + + + + + + + + + + + + + + + + +
PropertyTypeDescription
+ `signal?` + + `AbortSignal` + + Aborts the request (and any pending retries). +
diff --git a/docs/pages/reference/data-apis/src/type-aliases/SearchContractMetadataParams.mdx b/docs/pages/reference/data-apis/src/type-aliases/SearchContractMetadataParams.mdx new file mode 100644 index 0000000000..88da73d50d --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/SearchContractMetadataParams.mdx @@ -0,0 +1,14 @@ +--- +title: SearchContractMetadataParams +description: Overview of SearchContractMetadataParams +slug: wallets/reference/data-apis/type-aliases/SearchContractMetadataParams +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type SearchContractMetadataParams = NetworkScoped; +``` + +Defined in: [packages/data-apis/src/types.ts:225](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L225) diff --git a/docs/pages/reference/data-apis/src/type-aliases/SearchContractMetadataResult.mdx b/docs/pages/reference/data-apis/src/type-aliases/SearchContractMetadataResult.mdx new file mode 100644 index 0000000000..76baae7ca7 --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/SearchContractMetadataResult.mdx @@ -0,0 +1,14 @@ +--- +title: SearchContractMetadataResult +description: Overview of SearchContractMetadataResult +slug: wallets/reference/data-apis/type-aliases/SearchContractMetadataResult +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type SearchContractMetadataResult = any[]; +``` + +Defined in: [packages/data-apis/src/types.ts:227](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L227) diff --git a/docs/pages/reference/data-apis/src/type-aliases/SummarizeNftAttributesParams.mdx b/docs/pages/reference/data-apis/src/type-aliases/SummarizeNftAttributesParams.mdx new file mode 100644 index 0000000000..eedb28d511 --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/SummarizeNftAttributesParams.mdx @@ -0,0 +1,14 @@ +--- +title: SummarizeNftAttributesParams +description: Overview of SummarizeNftAttributesParams +slug: wallets/reference/data-apis/type-aliases/SummarizeNftAttributesParams +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type SummarizeNftAttributesParams = NetworkScoped; +``` + +Defined in: [packages/data-apis/src/types.ts:247](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L247) diff --git a/docs/pages/reference/data-apis/src/type-aliases/SummarizeNftAttributesResult.mdx b/docs/pages/reference/data-apis/src/type-aliases/SummarizeNftAttributesResult.mdx new file mode 100644 index 0000000000..2af500d854 --- /dev/null +++ b/docs/pages/reference/data-apis/src/type-aliases/SummarizeNftAttributesResult.mdx @@ -0,0 +1,14 @@ +--- +title: SummarizeNftAttributesResult +description: Overview of SummarizeNftAttributesResult +slug: wallets/reference/data-apis/type-aliases/SummarizeNftAttributesResult +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +type SummarizeNftAttributesResult = SummarizeNftAttributesResponse; +``` + +Defined in: [packages/data-apis/src/types.ts:249](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/types.ts#L249) diff --git a/docs/pages/reference/data-apis/src/variables/VERSION.mdx b/docs/pages/reference/data-apis/src/variables/VERSION.mdx new file mode 100644 index 0000000000..8bc404b538 --- /dev/null +++ b/docs/pages/reference/data-apis/src/variables/VERSION.mdx @@ -0,0 +1,14 @@ +--- +title: VERSION +description: Overview of VERSION +slug: wallets/reference/data-apis/variables/VERSION +layout: reference +--- + +{/* This file is auto-generated by TypeDoc. Do not edit manually. */} + +```ts +const VERSION: "5.0.3-alpha.0" = "5.0.3-alpha.0"; +``` + +Defined in: [packages/data-apis/src/version.ts:3](https://github.com/alchemyplatform/aa-sdk/blob/main/packages/data-apis/src/version.ts#L3) diff --git a/docs/pages/reference/modules.mdx b/docs/pages/reference/modules.mdx index c301a9751f..9f4a81fb67 100644 --- a/docs/pages/reference/modules.mdx +++ b/docs/pages/reference/modules.mdx @@ -13,6 +13,7 @@ layout: reference | :---------------------------------------------------------------------------------- | :---------- | | [aa-infra/src](aa-infra/src/README) | - | | [common/src](common/src/README) | - | +| [data-apis/src](data-apis/src/README) | - | | [smart-accounts/src](smart-accounts/src/README) | - | | [wallet-apis/src/exports](wallet-apis/src/exports/README) | - | | [wallet-apis/src/exports/experimental](wallet-apis/src/exports/experimental/README) | - | diff --git a/packages/data-apis/README.md b/packages/data-apis/README.md index cd7b4c5a69..33cfd75ec5 100644 --- a/packages/data-apis/README.md +++ b/packages/data-apis/README.md @@ -1,36 +1,104 @@ -# @alchemy/data-apis (MVP) +# @alchemy/data-apis -A vertical-slice prototype of the Data APIs SDK, built to prove the architecture -before scaling to the full v1 surface (Portfolio, Prices, NFT, Token, Transfers). +Alchemy's Data APIs — Portfolio, Prices, NFT, Token, and Transfers — as +typed, viem-style actions. **Currently published under the `alpha` dist-tag.** -## What this proves - -One method per seam, not full coverage: +```bash +npm install @alchemy/data-apis@alpha viem +``` -| Method | Channel | What it demonstrates | -| ------------------------------ | ----------------------------------------- | -------------------------------------------------------------------------------------------------------------- | -| `portfolio.getTokensByAddress` | REST → global `api.g.alchemy.com/data/v1` | Multi-network request bodies via `AlchemyRestClient`; networks are payload, the client's chain is not involved | -| `nft.getNftsForOwner` | REST → `{network}.g.alchemy.com/nft/v3` | Network-scoped endpoint resolution with per-request `network` override falling back to the client default | -| `transfers.getAssetTransfers` | JSON-RPC → `AlchemyTransport` | Plain viem action; network override derives a transport instance from `client.transport.config` | +## Quickstart -Plus the two entry points: +Two equivalent entry points: ```ts // Data-only developers (no viem knowledge required) -const data = createDataClient({ apiKey, network: "eth-mainnet" }); +import { createDataClient } from "@alchemy/data-apis"; + +const data = createDataClient({ + apiKey: process.env.ALCHEMY_API_KEY, + network: "eth-mainnet", // or `mainnet` from viem/chains, or "eip155:1" +}); + +// Developers already holding a viem client with an Alchemy transport +import { createClient } from "viem"; +import { mainnet } from "viem/chains"; +import { alchemyTransport } from "@alchemy/common"; +import { dataActions } from "@alchemy/data-apis"; -// Developers already on a viem client with an Alchemy transport const client = createClient({ chain: mainnet, - transport: alchemyTransport({ apiKey }), + transport: alchemyTransport({ apiKey: process.env.ALCHEMY_API_KEY }), }).extend(dataActions); ``` -Network inputs accept all three formats everywhere, resolved by -`resolveNetwork()` in `@alchemy/common`: a viem `Chain`, an Alchemy slug -(`"eth-mainnet"`), or CAIP-2 (`"eip155:1"`, `"solana:mainnet"`). The slug ↔ -chain-ID mapping is derived from the existing daikon-generated -`ALCHEMY_RPC_MAPPING` — no second registry. +Every action is also individually importable +(`import { getNftsForOwner } from "@alchemy/data-apis"`) for tree-shaking and +composability. + +## Namespaces + +```ts +// Portfolio — multi-network queries; networks travel per request +const tokens = await data.portfolio.getTokensByAddress({ + addresses: [ + { address: "0x...", networks: [mainnet, "base-mainnet", "solana-mainnet"] }, + ], +}); +// also: getTokenBalancesByAddress, getNftsByAddress, getNftContractsByAddress + +// Prices — chain-agnostic or address+network +const prices = await data.prices.getTokenPricesBySymbol({ + symbols: ["ETH", "USDC"], +}); +// also: getTokenPricesByAddress, getHistoricalTokenPrices + +// NFT — full v3 read surface (21 methods): ownership, metadata (+ batch), +// contracts/collections, owners, sales, floor price, search, spam/airdrop/rarity +const nfts = await data.nft.getNftsForOwner({ owner: "0x..." }); + +// Token — balances, metadata, allowance (JSON-RPC) +const balances = await data.token.getTokenBalances({ address: "0x..." }); + +// Transfers — historical transfer queries (JSON-RPC) +const transfers = await data.transfers.getAssetTransfers({ + category: ["erc20"], +}); +``` + +### Networks: three formats, everywhere + +Anywhere a network is accepted you can pass a viem `Chain`, an Alchemy slug +(`"eth-mainnet"`), or a CAIP-2 id (`"eip155:1"`, `"solana:mainnet"`) — +resolved by `resolveNetwork()` in `@alchemy/common`. Single-network methods +use the client's default network with a per-request `network` override; +multi-network methods (Portfolio, Prices-by-address) take networks in the +request itself. Registry-unknown slugs are passed through as an escape hatch. + +### Pagination + +Paginated methods have `*Pages` companions returning async generators that +manage cursors for you (and refuse to loop forever on repeated cursors): + +```ts +for await (const page of data.nft.getNftsForOwnerPages( + { owner: "0x..." }, + { maxPages: 10, signal: controller.signal }, +)) { + for (const nft of page.ownedNfts ?? []) { + // ... + } +} +``` + +### Errors + +Both channels (REST and JSON-RPC) normalize failures into `AlchemyApiError` +from `@alchemy/common`, carrying `status`, `code`, `requestId` (the +client-generated `X-Alchemy-Client-Request-Id`), and `retryAfter` when known. +REST requests retry 429/5xx/network failures with exponential backoff +(honoring `Retry-After`) and time out per attempt; pass an `AbortSignal` via +the per-request options to cancel. ## Generated internals @@ -42,15 +110,20 @@ hand-reviewed aliases, and `codegen.manifest.ts` maps spec operations to the generated surface — referencing a renamed/removed spec operation fails `pnpm generate` loudly. -## Companion changes in @alchemy/common +## Releasing -- `networks/networkRegistry.ts`: `resolveNetwork` + network types (slug map - derived from the registry URLs; to be emitted by ws-tools properly) -- `AlchemyRestClient` is now exported (was written for signer v5 but unexported) +While in alpha this package is deliberately **not** in `lerna.json`'s +fixed-version publish set, so the regular release workflow can't ship it as +`latest`. To publish an alpha: + +```bash +pnpm --filter @alchemy/data-apis build +cd packages/data-apis && pnpm publish --tag alpha +``` -## Deliberately out of scope (tracked in the data SDK scope plan) +Graduation checklist (when the team blesses a stable release): -- Rest client hardening: retries, timeouts, request-id, first-class query params -- Pagination iterators, error normalization, the SDK manifest, remaining methods -- ws-tools generator change to emit `{ slug, chainId, caip2 }` entries + - the `KnownAlchemyNetwork` union +1. Bump `version` to the shared monorepo version (drop the `-alpha.N` suffix). +2. Add `"packages/data-apis"` to `lerna.json`'s `packages` array. +3. Remove `publishConfig.tag`. +4. Announce the surface as semver-stable. diff --git a/packages/data-apis/package.json b/packages/data-apis/package.json index 4cba0ec8cc..c6c3882b14 100644 --- a/packages/data-apis/package.json +++ b/packages/data-apis/package.json @@ -1,7 +1,16 @@ { "name": "@alchemy/data-apis", - "version": "0.0.0", - "description": "Alchemy Data APIs SDK (Portfolio, Prices, NFT, Token, Transfers) — MVP", + "version": "5.0.3-alpha.0", + "description": "Alchemy Data APIs SDK: Portfolio, Prices, NFT, Token, and Transfers, as viem-style actions", + "keywords": [ + "alchemy", + "viem", + "nft", + "token", + "prices", + "portfolio", + "blockchain-data" + ], "author": "Alchemy", "license": "MIT", "private": false, @@ -53,7 +62,8 @@ }, "publishConfig": { "access": "public", - "registry": "https://registry.npmjs.org/" + "registry": "https://registry.npmjs.org/", + "tag": "alpha" }, "repository": { "type": "git", diff --git a/packages/data-apis/src/version.ts b/packages/data-apis/src/version.ts index 128c5e1f2d..5b39a18237 100644 --- a/packages/data-apis/src/version.ts +++ b/packages/data-apis/src/version.ts @@ -1,3 +1,3 @@ // This file is autogenerated by inject-version.ts. Any changes will be // overwritten on commit! -export const VERSION = "0.0.0"; +export const VERSION = "5.0.3-alpha.0"; diff --git a/scripts/generate-typedoc-yaml.ts b/scripts/generate-typedoc-yaml.ts index c977ac8745..f385c387dc 100644 --- a/scripts/generate-typedoc-yaml.ts +++ b/scripts/generate-typedoc-yaml.ts @@ -56,6 +56,7 @@ type TypeSections = Record; const PACKAGE_DISPLAY_NAMES: Record = { "aa-infra": "AA Infra", common: "Alchemy Common", + "data-apis": "Data APIs", "smart-accounts": "Smart Accounts", "wallet-apis": "Wallet APIs", } as const; @@ -65,6 +66,7 @@ const PACKAGE_DISPLAY_NAMES: Record = { const PACKAGES_INCLUDED_IN_NAV: string[] = [ "wallet-apis", "smart-accounts", + "data-apis", "aa-infra", "common", ]; diff --git a/tsconfig.typedoc.json b/tsconfig.typedoc.json index 4ebff17a81..26993b111f 100644 --- a/tsconfig.typedoc.json +++ b/tsconfig.typedoc.json @@ -11,6 +11,7 @@ "include": [ "packages/aa-infra/src/**/*", "packages/common/src/**/*", + "packages/data-apis/src/**/*", "packages/smart-accounts/src/**/*", "packages/wallet-apis/src/**/*" ], diff --git a/typedoc.json b/typedoc.json index 42b28064a2..b46a2319b6 100644 --- a/typedoc.json +++ b/typedoc.json @@ -8,6 +8,7 @@ "entryPoints": [ "packages/aa-infra/src/index.ts", "packages/common/src/index.ts", + "packages/data-apis/src/index.ts", "packages/smart-accounts/src/index.ts", "packages/wallet-apis/src/exports/index.ts", "packages/wallet-apis/src/exports/experimental.ts", From 90c0eee99d7d350070e6f5b17d73c072474a68da Mon Sep 17 00:00:00 2001 From: blake duncan Date: Wed, 10 Jun 2026 11:14:59 -0400 Subject: [PATCH 7/8] ci: codegen drift gate + spec-bump workflow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - on-pull-request: 'pnpm generate && git diff --exit-code' over generated output and spec snapshots, mirroring the existing docs:sdk drift check — fails if generation is stale or snapshots were hand-edited (offline, no new secrets) - bump-api-specs (workflow_dispatch): checks out the public docs repo at main, re-snapshots, regenerates, and opens a PR via create-pull-request; manifest validation hard-fails the run when an SDK-referenced operation was renamed/removed upstream Co-Authored-By: Claude Fable 5 --- .github/workflows/bump-api-specs.yml | 63 +++++++++++++++++++++++++++ .github/workflows/on-pull-request.yml | 6 +++ 2 files changed, 69 insertions(+) create mode 100644 .github/workflows/bump-api-specs.yml diff --git a/.github/workflows/bump-api-specs.yml b/.github/workflows/bump-api-specs.yml new file mode 100644 index 0000000000..76fa4af8db --- /dev/null +++ b/.github/workflows/bump-api-specs.yml @@ -0,0 +1,63 @@ +name: Bump API spec snapshots + +# Re-snapshots the bundled OpenAPI/OpenRPC specs from alchemyplatform/docs +# (public) at its current main, regenerates SDK internals, and opens a PR if +# anything changed. The manifest validation inside `pnpm generate` hard-fails +# the run if an operation the SDK depends on was renamed or removed — that +# failure is the drift alarm and needs a human decision, not a merge. +# +# Manual for now; switch `workflow_dispatch` to a schedule (or a +# repository_dispatch from the docs repo's publish workflow) once the cadence +# is settled. + +on: + workflow_dispatch: + +jobs: + bump-specs: + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + steps: + - uses: actions/checkout@v4 + + - name: Checkout docs repo + uses: actions/checkout@v4 + with: + repository: alchemyplatform/docs + path: .docs-checkout + + - name: Setup + uses: ./.github/actions/setup + + - name: Install docs dependencies + run: pnpm install --ignore-scripts + working-directory: .docs-checkout + + - name: Snapshot specs from docs main + run: pnpm tsx packages/api-codegen/src/cli.ts snapshot --docs "$GITHUB_WORKSPACE/.docs-checkout" + + - name: Regenerate SDK internals + run: | + pnpm run build:libs + pnpm run generate + + - name: Remove docs checkout before PR + run: rm -rf .docs-checkout + + - name: Open PR if anything changed + uses: peter-evans/create-pull-request@v6 + with: + commit-message: "chore(api-codegen): bump spec snapshots from docs main" + title: "chore(api-codegen): bump API spec snapshots" + body: | + Automated re-snapshot of the bundled OpenAPI/OpenRPC specs from + `alchemyplatform/docs` main, plus regenerated SDK internals. + + Review the `packages/api-codegen/specs/` diff for what moved + upstream and the `src/generated/` diff for the type impact. + Public types in `packages/data-apis/src/types.ts` are aliases — + check whether any public-surface change warrants a semver note. + branch: chore/bump-api-specs + delete-branch: true diff --git a/.github/workflows/on-pull-request.yml b/.github/workflows/on-pull-request.yml index 227d15dcb7..ad879fbf10 100644 --- a/.github/workflows/on-pull-request.yml +++ b/.github/workflows/on-pull-request.yml @@ -186,6 +186,12 @@ jobs: - name: Typecheck Test run: pnpm run test:typecheck + - name: Check generated API code is up to date + run: | + pnpm run generate + git diff --exit-code packages/*/src/generated packages/api-codegen/specs || \ + (echo "::error::Generated API code is out of date or spec snapshots were hand-edited. Run 'pnpm generate' and commit the changes." && exit 1) + - name: Check SDK reference docs are up to date run: | pnpm run docs:sdk From 66c0b88d4b8246afa9b97137ab56ea95373bb04d Mon Sep 17 00:00:00 2001 From: blake duncan Date: Wed, 10 Jun 2026 11:20:46 -0400 Subject: [PATCH 8/8] test(data-apis): type tests, export boundary, expanded live smoke suite MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - index.test-d.ts: 7 vitest typecheck tests (client/decorator surface equivalence, AlchemyTransport constraint enforcement, spec-accurate result shapes, three-format network params, Pages generator types); data-apis vitest config now enables typecheck under TYPECHECK=true like the shared config - exports.test.ts: locks the package's runtime export surface; generated internals barrel stays internal - smoke test grown 14 → 30 live tests: every namespace exercised against the real API (portfolio x3 new, prices x3, nft x5 new, token x3) plus two-page pagination walks for nft and transfers companions — all passing Co-Authored-By: Claude Fable 5 --- packages/data-apis/scripts/smoke-test.ts | 176 +++++++++++++++++++++++ packages/data-apis/src/exports.test.ts | 60 ++++++++ packages/data-apis/src/index.test-d.ts | 75 ++++++++++ packages/data-apis/vitest.config.ts | 7 + 4 files changed, 318 insertions(+) create mode 100644 packages/data-apis/src/exports.test.ts create mode 100644 packages/data-apis/src/index.test-d.ts diff --git a/packages/data-apis/scripts/smoke-test.ts b/packages/data-apis/scripts/smoke-test.ts index eb8fc81e75..9314dc6911 100644 --- a/packages/data-apis/scripts/smoke-test.ts +++ b/packages/data-apis/scripts/smoke-test.ts @@ -249,6 +249,182 @@ await test("nft via raw viem client", async () => { ); }); +console.log("\n\x1b[1mportfolio — new methods\x1b[0m"); + +await test("getTokenBalancesByAddress", async () => { + const result = await clientBySlug.portfolio.getTokenBalancesByAddress({ + addresses: [{ address: VITALIK, networks: ["eth-mainnet"] }], + }); + assert(Array.isArray(result.data.tokens), "data.tokens should be an array"); +}); + +await test("getNftsByAddress (paginated body method)", async () => { + const result = await clientBySlug.portfolio.getNftsByAddress({ + addresses: [{ address: VITALIK, networks: ["eth-mainnet"] }], + pageSize: 2, + }); + assert( + Array.isArray(result.data.ownedNfts), + "data.ownedNfts should be an array", + ); +}); + +await test("getNftContractsByAddress", async () => { + const result = await clientBySlug.portfolio.getNftContractsByAddress({ + addresses: [{ address: VITALIK, networks: ["eth-mainnet"] }], + pageSize: 2, + }); + assert( + Array.isArray(result.data.contracts), + "data.contracts should be an array", + ); +}); + +console.log("\n\x1b[1mprices\x1b[0m"); + +await test("getTokenPricesBySymbol (chain-agnostic)", async () => { + const result = await clientBySlug.prices.getTokenPricesBySymbol({ + symbols: ["ETH"], + }); + assert(Array.isArray(result.data), "data should be an array"); + assert((result.data ?? []).length > 0, "expected a price for ETH"); +}); + +await test("getTokenPricesByAddress (network in entry)", async () => { + // USDC on mainnet + const result = await clientBySlug.prices.getTokenPricesByAddress({ + addresses: [ + { + address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + network: mainnet, + }, + ], + }); + assert(Array.isArray(result.data), "data should be an array"); +}); + +await test("getHistoricalTokenPrices (symbol form)", async () => { + const end = new Date(); + const start = new Date(end.getTime() - 24 * 60 * 60 * 1000); + const result = await clientBySlug.prices.getHistoricalTokenPrices({ + symbol: "ETH", + startTime: start.toISOString(), + endTime: end.toISOString(), + interval: "1h", + }); + assert(Array.isArray(result.data), "data should be an array"); +}); + +console.log("\n\x1b[1mnft — new methods\x1b[0m"); + +// BAYC — stable, well-known contract +const BAYC = "0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D"; + +await test("getContractMetadata", async () => { + const result = await clientBySlug.nft.getContractMetadata({ + contractAddress: BAYC, + }); + assert( + typeof result.address === "string", + "contract metadata should include the address", + ); +}); + +await test("getNftMetadata", async () => { + const result = await clientBySlug.nft.getNftMetadata({ + contractAddress: BAYC, + tokenId: "1", + }); + assert(result.tokenId === "1", "should return the requested token"); +}); + +await test("getFloorPrice", async () => { + const result = await clientBySlug.nft.getFloorPrice({ + contractAddress: BAYC, + }); + assert( + typeof result === "object" && result != null, + "should return floor prices", + ); +}); + +await test("isSpamContract", async () => { + const result = await clientBySlug.nft.isSpamContract({ + contractAddress: BAYC, + }); + assert(typeof result.isSpamContract === "boolean", "should classify spam"); +}); + +await test("getNftsForContract with pageSize-style limit", async () => { + const result = await clientBySlug.nft.getNftsForContract({ + contractAddress: BAYC, + limit: 2, + withMetadata: false, + }); + assert(Array.isArray(result.nfts), "nfts should be an array"); + assert((result.nfts ?? []).length <= 2, "should respect limit"); +}); + +console.log("\n\x1b[1mtoken (JSON-RPC)\x1b[0m"); + +// USDC contract on mainnet +const USDC = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"; + +await test("getTokenBalances", async () => { + const result = await clientBySlug.token.getTokenBalances({ + address: VITALIK, + tokenSpec: [USDC], + }); + assert( + Array.isArray(result.tokenBalances), + "tokenBalances should be an array", + ); +}); + +await test("getTokenMetadata", async () => { + const result = await clientBySlug.token.getTokenMetadata({ + contractAddress: USDC, + }); + assert(result.symbol === "USDC", "should return USDC metadata"); +}); + +await test("getTokenAllowance", async () => { + const result = await clientBySlug.token.getTokenAllowance({ + contract: USDC, + owner: VITALIK, + spender: VITALIK, + }); + assert(typeof result === "string", "allowance should be a decimal string"); +}); + +console.log("\n\x1b[1mpagination companions\x1b[0m"); + +await test("nft.getNftsForOwnerPages walks two pages", async () => { + let pages = 0; + let lastPageKey: string | undefined; + for await (const page of clientBySlug.nft.getNftsForOwnerPages( + { owner: VITALIK, pageSize: 5, withMetadata: false }, + { maxPages: 2 }, + )) { + pages += 1; + if (pages === 1) lastPageKey = page.pageKey; + } + assert(pages === 2, `expected 2 pages, got ${pages}`); + assert(!!lastPageKey, "first page should carry a cursor"); +}); + +await test("transfers.getAssetTransfersPages walks two pages", async () => { + let pages = 0; + for await (const page of clientBySlug.transfers.getAssetTransfersPages( + { fromAddress: VITALIK, category: ["external"], maxCount: "0x2" }, + { maxPages: 2 }, + )) { + pages += 1; + assert(Array.isArray(page.transfers), "each page carries transfers"); + } + assert(pages === 2, `expected 2 pages, got ${pages}`); +}); + // ─── Summary ────────────────────────────────────────────────────────────────── console.log(`\n${"─".repeat(50)}`); diff --git a/packages/data-apis/src/exports.test.ts b/packages/data-apis/src/exports.test.ts new file mode 100644 index 0000000000..1d2c373fbd --- /dev/null +++ b/packages/data-apis/src/exports.test.ts @@ -0,0 +1,60 @@ +import { describe, expect, it } from "vitest"; +import * as packageExports from "./index.js"; + +describe("package export boundary", () => { + it("exposes exactly the intended runtime exports", () => { + expect(Object.keys(packageExports).sort()).toEqual( + [ + "VERSION", + "computeRarity", + "createDataClient", + "dataActions", + "getAssetTransfers", + "getAssetTransfersPages", + "getCollectionMetadata", + "getCollectionsForOwner", + "getCollectionsForOwnerPages", + "getContractMetadata", + "getContractMetadataBatch", + "getContractsForOwner", + "getContractsForOwnerPages", + "getFloorPrice", + "getHistoricalTokenPrices", + "getNftContractsByAddress", + "getNftContractsByAddressPages", + "getNftMetadata", + "getNftMetadataBatch", + "getNftSales", + "getNftSalesPages", + "getNftsByAddress", + "getNftsByAddressPages", + "getNftsForCollection", + "getNftsForCollectionPages", + "getNftsForContract", + "getNftsForContractPages", + "getNftsForOwner", + "getNftsForOwnerPages", + "getOwnersForContract", + "getOwnersForNft", + "getSpamContracts", + "getTokenAllowance", + "getTokenBalances", + "getTokenBalancesByAddress", + "getTokenMetadata", + "getTokenPricesByAddress", + "getTokenPricesBySymbol", + "getTokensByAddress", + "isAirdropNft", + "isHolderOfContract", + "isSpamContract", + "searchContractMetadata", + "summarizeNftAttributes", + ].sort(), + ); + }); + + it("does not re-export the generated internals barrel", () => { + expect(Object.keys(packageExports)).not.toContain("operations"); + expect(Object.keys(packageExports)).not.toContain("paths"); + }); +}); diff --git a/packages/data-apis/src/index.test-d.ts b/packages/data-apis/src/index.test-d.ts new file mode 100644 index 0000000000..eabc9b7009 --- /dev/null +++ b/packages/data-apis/src/index.test-d.ts @@ -0,0 +1,75 @@ +import { expectTypeOf, test } from "vitest"; +import { createClient, http, type Chain, type Client } from "viem"; +import { mainnet } from "viem/chains"; +import { alchemyTransport, type AlchemyTransport } from "@alchemy/common"; +import { + createDataClient, + dataActions, + getNftsForOwner, + type AlchemyDataClient, + type DataActions, + type GetAssetTransfersResult, + type GetNftsForOwnerParams, + type GetNftsForOwnerResult, + type GetTokensByAddressResult, +} from "./index.js"; + +declare const dataClient: AlchemyDataClient; +declare const baseClient: Client; + +test("createDataClient returns a viem client extended with DataActions", () => { + expectTypeOf( + createDataClient({ apiKey: "key", network: "eth-mainnet" }), + ).toEqualTypeOf(); + expectTypeOf(dataClient).toMatchTypeOf(); +}); + +test("decorator path matches the convenience client surface", () => { + const extended = createClient({ + chain: mainnet, + transport: alchemyTransport({ apiKey: "key" }), + }).extend(dataActions); + expectTypeOf(extended.nft.getNftsForOwner).toEqualTypeOf< + AlchemyDataClient["nft"]["getNftsForOwner"] + >(); +}); + +test("dataActions requires an Alchemy transport client", () => { + const plainHttp = createClient({ chain: mainnet, transport: http() }); + // @ts-expect-error plain http transport is not an AlchemyTransport + dataActions(plainHttp); + dataActions(baseClient); +}); + +test("results carry spec-accurate shapes", () => { + expectTypeOf().toMatchTypeOf<{ + tokens?: unknown[]; + pageKey?: string; + }>(); + // the transfers notFound string branch is collapsed away + expectTypeOf().not.toMatchTypeOf(); +}); + +test("network-scoped params accept all three network formats", () => { + expectTypeOf().toMatchTypeOf< + Chain | string | undefined + >(); + // bracketed wire keys are exposed unbracketed + expectTypeOf().toMatchTypeOf<{ + owner: string; + contractAddresses?: string[]; + excludeFilters?: ("SPAM" | "AIRDROPS")[]; + }>(); +}); + +test("standalone actions return the same results as the decorator", () => { + expectTypeOf(getNftsForOwner).returns.toEqualTypeOf< + Promise + >(); +}); + +test("paginated companions yield pages", () => { + expectTypeOf(dataClient.nft.getNftsForOwnerPages).returns.toEqualTypeOf< + AsyncGenerator + >(); +}); diff --git a/packages/data-apis/vitest.config.ts b/packages/data-apis/vitest.config.ts index 160b2a76d1..22e22c093d 100644 --- a/packages/data-apis/vitest.config.ts +++ b/packages/data-apis/vitest.config.ts @@ -1,10 +1,17 @@ import { defineProject } from "vitest/config"; +const typechecking = process.env["TYPECHECK"] === "true"; + export default defineProject({ test: { name: "alchemy/data-apis", globals: true, include: ["src/**/*.test.ts"], + typecheck: { + enabled: typechecking, + only: typechecking, + ignoreSourceErrors: true, + }, // Unit tests stub fetch; no anvil/bundler setup needed (same as common) setupFiles: [], globalSetup: undefined,