|
| 1 | +import { getErrorMsg } from '../utils'; |
| 2 | +import { |
| 3 | + BitteToolBuilder, |
| 4 | + BitteToolResult, |
| 5 | + GqlFetchResult, |
| 6 | + NearNetworkId, |
| 7 | +} from '../types'; |
| 8 | + |
| 9 | +export const GRAPH_ENDPOINTS = { |
| 10 | + mainnet: 'https://graph.mintbase.xyz/', |
| 11 | + testnet: 'https://graph.mintbase.xyz/testnet', |
| 12 | +}; |
| 13 | + |
| 14 | +type SubmitQueryParams = { |
| 15 | + query: string; |
| 16 | + network: NearNetworkId; |
| 17 | +}; |
| 18 | + |
| 19 | +export const submitQueryPrimitive: BitteToolBuilder< |
| 20 | + void, |
| 21 | + SubmitQueryParams, |
| 22 | + GqlFetchResult<unknown> |
| 23 | +> = () => ({ |
| 24 | + toolSpec: { |
| 25 | + function: { |
| 26 | + name: 'submit-query', |
| 27 | + description: `Generate and submit GraphQL queries based on schema. |
| 28 | + - Limit results to 5 unless specified (max 20) |
| 29 | + - Fetch aggregations with '<field-name>_aggregate' |
| 30 | + - Always fetch 'metadata_id' for NFTs |
| 31 | + - Use model/view names as main query fields |
| 32 | + - Include relevant fields in selection set |
| 33 | +
|
| 34 | + Example: |
| 35 | + query FetchRecentListings { |
| 36 | + mb_views_active_listings(order_by: {created_at: desc}, limit: 5) { |
| 37 | + media title price created_at nft_contract_id token_id metadata_id |
| 38 | + } |
| 39 | + } |
| 40 | + `, |
| 41 | + parameters: { |
| 42 | + type: 'object', |
| 43 | + required: ['query', 'network'], |
| 44 | + properties: { |
| 45 | + query: { |
| 46 | + type: 'string', |
| 47 | + description: `GraphQL query based on this schema: |
| 48 | + SharedNFTFields: nft_contract_id, token_id, receipt_id, timestamp, reference, reference_hash, media, media_hash, title, description, extra, content_flag |
| 49 | + SharedContractFields: name, symbol, icon, spec, base_uri, owner_id, is_mintbase |
| 50 | +
|
| 51 | + Models: |
| 52 | + mb_store_minters: {...SharedNFTFields, minter_id} |
| 53 | + nft_approvals: {...SharedNFTFields, approved_account_id, approval_id} |
| 54 | + nft_attributes: {nft_metadata_id, ...SharedNFTFields, attribute_type, attribute_value, attribute_display_type} |
| 55 | + nft_contracts: {id, ...SharedContractFields, reference, reference_hash, created_at, created_receipt_id, content_flag, category} |
| 56 | + nft_metadata: {id, ...SharedNFTFields, reference_blob, minter} |
| 57 | +
|
| 58 | + Views: |
| 59 | + mb_views_nft_metadata: {id, ...SharedNFTFields, ...SharedContractFields, reference_blob, metadata_content_flag, nft_contract_reference, nft_contract_created_at, nft_contract_content_flag} |
| 60 | + mb_views_active_listings: {...SharedNFTFields, market_id, approval_id, created_at, kind, price, currency, listed_by, metadata_id, minter, reference_blob} |
| 61 | + mb_views_nft_tokens: {...SharedNFTFields, ...SharedContractFields, owner, mint_memo, last_transfer_timestamp, last_transfer_receipt_id, minted_timestamp, minted_receipt_id, burned_timestamp, burned_receipt_id, minter, copies, issued_at, expires_at, starts_at, updated_at, metadata_id, reference_blob, metadata_content_flag, nft_contract_reference, nft_contract_created_at, nft_contract_content_flag, royalties_percent, royalties, splits} |
| 62 | + mb_views_nft_tokens_with_listing: {...SharedNFTFields, owner, metadata_id, price, currency, reference_blob} |
| 63 | + mb_views_active_listings_by_contract: {...SharedNFTFields, market_id, approval_id, price, currency, created_at, metadata_id, listed_by, total_listings}`, |
| 64 | + }, |
| 65 | + network: { |
| 66 | + type: 'string', |
| 67 | + enum: ['testnet', 'mainnet'], |
| 68 | + default: 'mainnet', |
| 69 | + description: 'Network to query.', |
| 70 | + }, |
| 71 | + }, |
| 72 | + }, |
| 73 | + }, |
| 74 | + type: 'function', |
| 75 | + }, |
| 76 | + execute: async ({ |
| 77 | + query, |
| 78 | + network, |
| 79 | + }: SubmitQueryParams): Promise<BitteToolResult<GqlFetchResult<unknown>>> => { |
| 80 | + const mintbaseGraphUrl = GRAPH_ENDPOINTS[network]; |
| 81 | + |
| 82 | + try { |
| 83 | + const request = await fetch(mintbaseGraphUrl, { |
| 84 | + method: 'POST', |
| 85 | + headers: { |
| 86 | + 'Content-Type': 'application/json', |
| 87 | + 'mb-api-key': 'omni-site', |
| 88 | + }, |
| 89 | + body: JSON.stringify({ |
| 90 | + query, |
| 91 | + network, |
| 92 | + }), |
| 93 | + }); |
| 94 | + |
| 95 | + const queryResponse: GqlFetchResult<unknown> = await request.json(); |
| 96 | + |
| 97 | + const queryData = queryResponse.data; |
| 98 | + |
| 99 | + if (queryData) { |
| 100 | + return { |
| 101 | + data: queryData, |
| 102 | + }; |
| 103 | + } |
| 104 | + |
| 105 | + return { |
| 106 | + error: queryResponse.error || 'Query returned no data or error', |
| 107 | + }; |
| 108 | + } catch (error) { |
| 109 | + return { |
| 110 | + error: getErrorMsg(error), |
| 111 | + }; |
| 112 | + } |
| 113 | + }, |
| 114 | +}); |
0 commit comments