From 108bad9e02ddfbd51bb323564d8a9b60ac42d94e Mon Sep 17 00:00:00 2001 From: gmemez Date: Thu, 6 Feb 2025 03:04:31 +0700 Subject: [PATCH 1/6] add recursive endpoints, docs improvements --- docs/api-docs.json | 1702 +++++++++++++++++++++ docs/favicon.ico | Bin 0 -> 13375 bytes docs/generateHtml.ts | 359 ++--- docs/generateMethodsDocs.ts | 199 +-- docs/generateTypesDocs.ts | 25 +- docs/scripts.js | 99 ++ docs/styles.css | 213 +++ docs/utils/doc-parser.ts | 59 + src/api.ts | 82 +- src/client.ts | 323 +++- src/schemas/block.ts | 31 + src/schemas/inscription.ts | 47 +- src/schemas/output.ts | 18 +- src/schemas/rune.ts | 6 + src/schemas/transaction.ts | 7 + src/test/integration/api.test.ts | 45 +- src/test/integration/recursiveApi.test.ts | 442 ++++++ src/test/unit/schemas.test.ts | 229 ++- src/types/index.ts | 65 +- 19 files changed, 3483 insertions(+), 468 deletions(-) create mode 100644 docs/api-docs.json create mode 100644 docs/favicon.ico create mode 100644 docs/scripts.js create mode 100644 docs/styles.css create mode 100644 docs/utils/doc-parser.ts create mode 100644 src/test/integration/recursiveApi.test.ts diff --git a/docs/api-docs.json b/docs/api-docs.json new file mode 100644 index 0000000..d5d8504 --- /dev/null +++ b/docs/api-docs.json @@ -0,0 +1,1702 @@ +{ + "classMethods": [ + { + "name": "getAddressInfo", + "parameters": [ + { + "name": "address", + "type": "string", + "description": "" + } + ], + "description": "Retrieves information about a specific address including its outputs, inscriptions, and rune balances.", + "endpoint": "/address/{address}", + "httpMethod": "GET", + "returnType": "Promise", + "recursive": false + }, + { + "name": "getBlockInfo", + "parameters": [ + { + "name": "heightOrHash", + "type": "number | BlockHash", + "description": "" + } + ], + "description": "Fetches details about a specific block by its height or hash.", + "endpoint": "/block/{heightOrHash}", + "httpMethod": "GET", + "returnType": "Promise", + "recursive": false + }, + { + "name": "getBlockInfoRecursive", + "parameters": [ + { + "name": "heightOrHash", + "type": "number | string", + "description": "" + } + ], + "description": "Gets detailed block information using the recursive endpoint.", + "endpoint": "/r/blockinfo/{heightOrHash}", + "httpMethod": "GET", + "returnType": "Promise", + "recursive": true + }, + { + "name": "getBlockCount", + "parameters": [], + "description": "Retrieves the total number of blocks in the blockchain.", + "endpoint": "/blockcount", + "httpMethod": "GET", + "returnType": "Promise", + "recursive": false + }, + { + "name": "getBlockHash", + "parameters": [], + "description": "Gets the hash of the latest block.", + "endpoint": "/blockhash", + "httpMethod": "GET", + "returnType": "Promise", + "recursive": false + }, + { + "name": "getBlockHashRecursive", + "parameters": [], + "description": "Gets the latest block hash using the recursive endpoint.", + "endpoint": "/r/blockhash", + "httpMethod": "GET", + "returnType": "Promise", + "recursive": true + }, + { + "name": "getBlockHashByHeight", + "parameters": [ + { + "name": "height", + "type": "number", + "description": "" + } + ], + "description": "Gets the hash of a block at the specified height.", + "endpoint": "/blockhash/{height}", + "httpMethod": "GET", + "returnType": "Promise", + "recursive": false + }, + { + "name": "getBlockHashByHeightRecursive", + "parameters": [ + { + "name": "height", + "type": "number", + "description": "" + } + ], + "description": "Gets the block hash using the recursive endpoint.", + "endpoint": "/r/blockhash/{height}", + "httpMethod": "GET", + "returnType": "Promise", + "recursive": true + }, + { + "name": "getBlockHeight", + "parameters": [], + "description": "Gets the height of the latest block.", + "endpoint": "/blockheight", + "httpMethod": "GET", + "returnType": "Promise", + "recursive": false + }, + { + "name": "getBlockHeightRecursive", + "parameters": [], + "description": "Gets the latest block height using the recursive endpoint.", + "endpoint": "/r/blockheight", + "httpMethod": "GET", + "returnType": "Promise", + "recursive": true + }, + { + "name": "getBlocksLatest", + "parameters": [], + "description": "Returns the height of the latest block, the blockhashes of the last 100 blocks, and featured inscriptions from them.", + "endpoint": "/blocks", + "httpMethod": "GET", + "returnType": "Promise", + "recursive": false + }, + { + "name": "getBlockTime", + "parameters": [], + "description": "Gets the timestamp of the latest block.", + "endpoint": "/blocktime", + "httpMethod": "GET", + "returnType": "Promise", + "recursive": false + }, + { + "name": "getBlockTimeRecursive", + "parameters": [], + "description": "Gets block time using the recursive endpoint.", + "endpoint": "/r/blocktime", + "httpMethod": "GET", + "returnType": "Promise", + "recursive": true + }, + { + "name": "getInscriptionInfo", + "parameters": [ + { + "name": "id", + "type": "string", + "description": "" + } + ], + "description": "Retrieves information about a specific inscription by its ID.", + "endpoint": "/inscription/{id}", + "httpMethod": "GET", + "returnType": "Promise", + "recursive": false + }, + { + "name": "getInscriptionRecursive", + "parameters": [ + { + "name": "id", + "type": "string", + "description": "" + } + ], + "description": "Gets recursive inscription information.", + "endpoint": "/r/inscription/{id}", + "httpMethod": "GET", + "returnType": "Promise", + "recursive": true + }, + { + "name": "getInscriptions", + "parameters": [], + "description": "Gets a list of the 100 most recent inscriptions.", + "endpoint": "/inscriptions", + "httpMethod": "GET", + "returnType": "Promise", + "recursive": false + }, + { + "name": "getInscriptionsByIds", + "parameters": [ + { + "name": "ids", + "type": "string[]", + "description": "" + } + ], + "description": "Retrieves information about multiple inscriptions by their IDs.", + "endpoint": "/inscriptions", + "httpMethod": "POST", + "returnType": "Promise", + "recursive": false + }, + { + "name": "getInscriptionsByPage", + "parameters": [ + { + "name": "page", + "type": "number", + "description": "" + } + ], + "description": "Gets inscriptions for a specific page number in paginated results.", + "endpoint": "/inscriptions/{page}", + "httpMethod": "GET", + "returnType": "Promise", + "recursive": false + }, + { + "name": "getInscriptionsByBlock", + "parameters": [ + { + "name": "height", + "type": "number", + "description": "" + } + ], + "description": "Gets all inscriptions in a specific block.", + "endpoint": "/inscriptions/block/{height}", + "httpMethod": "GET", + "returnType": "Promise", + "recursive": false + }, + { + "name": "getInscriptionOnSat", + "parameters": [ + { + "name": "number", + "type": "number", + "description": "" + }, + { + "name": "index", + "type": "number", + "description": "" + } + ], + "description": "Gets ID of a specific inscription at an index by sat number. The inscription id at index of all inscriptions on a sat. Index may be a negative number to index from the back. 0 being the first and -1 being the most recent for example. Requires index with --index-sats flag.", + "endpoint": "/r/sat/{number}/at/{index}", + "httpMethod": "GET", + "returnType": "Promise", + "recursive": true + }, + { + "name": "getInscriptionsOnSat", + "parameters": [ + { + "name": "number", + "type": "number", + "description": "" + } + ], + "description": "Gets the first 100 inscription ids on a sat. Requires index with --index-sats flag.", + "endpoint": "/r/sat/{number}", + "httpMethod": "GET", + "returnType": "Promise", + "recursive": true + }, + { + "name": "getInscriptionsOnSatByPage", + "parameters": [ + { + "name": "number", + "type": "number", + "description": "" + }, + { + "name": "page", + "type": "number", + "description": "" + } + ], + "description": "Gets paginated inscription ids for a specific satoshi.", + "endpoint": "/r/sat/{number}/{page}", + "httpMethod": "GET", + "returnType": "Promise", + "recursive": true + }, + { + "name": "getChild", + "parameters": [ + { + "name": "id", + "type": "string", + "description": "" + }, + { + "name": "child", + "type": "number", + "description": "" + } + ], + "description": "Gets a specific child inscription of a parent inscription.", + "endpoint": "/inscription/{id}/{child}", + "httpMethod": "GET", + "returnType": "Promise", + "recursive": false + }, + { + "name": "getChildren", + "parameters": [ + { + "name": "id", + "type": "string", + "description": "" + } + ], + "description": "Gets first 100 child inscriptions IDs.", + "endpoint": "/r/children/{id}", + "httpMethod": "GET", + "returnType": "Promise", + "recursive": true + }, + { + "name": "getChildrenByPage", + "parameters": [ + { + "name": "id", + "type": "string", + "description": "" + }, + { + "name": "page", + "type": "number", + "description": "" + } + ], + "description": "Gets paginated child inscription IDs.", + "endpoint": "/r/children/{id}/{page}", + "httpMethod": "GET", + "returnType": "Promise", + "recursive": true + }, + { + "name": "getChildrenInfo", + "parameters": [ + { + "name": "id", + "type": "string", + "description": "" + } + ], + "description": "Gets details of the first 100 child inscriptions.", + "endpoint": "/r/children/{id}/inscriptions", + "httpMethod": "GET", + "returnType": "Promise", + "recursive": true + }, + { + "name": "getChildrenInfoByPage", + "parameters": [ + { + "name": "id", + "type": "string", + "description": "" + }, + { + "name": "page", + "type": "number", + "description": "" + } + ], + "description": "Gets paginated detailed child inscription information.", + "endpoint": "/r/children/{id}/inscriptions/{page}", + "httpMethod": "GET", + "returnType": "Promise", + "recursive": true + }, + { + "name": "getParents", + "parameters": [ + { + "name": "id", + "type": "string", + "description": "" + } + ], + "description": "Gets parent inscription IDs.", + "endpoint": "/r/parents/{id}", + "httpMethod": "GET", + "returnType": "Promise", + "recursive": true + }, + { + "name": "getParentsByPage", + "parameters": [ + { + "name": "id", + "type": "string", + "description": "" + }, + { + "name": "page", + "type": "number", + "description": "" + } + ], + "description": "Gets paginated parent inscription IDs.", + "endpoint": "/r/parents/{id}/{page}", + "httpMethod": "GET", + "returnType": "Promise", + "recursive": true + }, + { + "name": "getOutput", + "parameters": [ + { + "name": "outpoint", + "type": "string", + "description": "" + } + ], + "description": "Retrieves information about a specific UTXO.", + "endpoint": "/output/{outpoint}", + "httpMethod": "GET", + "returnType": "Promise", + "recursive": false + }, + { + "name": "getOutputAssets", + "parameters": [ + { + "name": "outpoint", + "type": "string", + "description": "" + } + ], + "description": "Gets assets held by an UTXO.", + "endpoint": "/r/utxo/{outpoint}", + "httpMethod": "GET", + "returnType": "Promise", + "recursive": true + }, + { + "name": "getOutputs", + "parameters": [ + { + "name": "outpoints", + "type": "string[]", + "description": "" + } + ], + "description": "Gets information about multiple UTXOs.", + "endpoint": "/outputs", + "httpMethod": "POST", + "returnType": "Promise", + "recursive": false + }, + { + "name": "getOutputsByAddress", + "parameters": [ + { + "name": "address", + "type": "string", + "description": "" + }, + { + "name": "type", + "type": "OutputType", + "description": "" + } + ], + "description": "Gets all UTXOs for a specific address, optionally filtered by type.", + "endpoint": "/outputs/{address}", + "httpMethod": "GET", + "returnType": "Promise", + "recursive": false + }, + { + "name": "getRune", + "parameters": [ + { + "name": "name", + "type": "string", + "description": "" + } + ], + "description": "Gets information about a specific rune by name.", + "endpoint": "/rune/{name}", + "httpMethod": "GET", + "returnType": "Promise", + "recursive": false + }, + { + "name": "getRunesLatest", + "parameters": [], + "description": "Gets a list of the 100 most recent runes.", + "endpoint": "/runes", + "httpMethod": "GET", + "returnType": "Promise", + "recursive": false + }, + { + "name": "getRunesByPage", + "parameters": [ + { + "name": "page", + "type": "number", + "description": "" + } + ], + "description": "Gets runes for a specific page number in paginated results.", + "endpoint": "/runes/{page}", + "httpMethod": "GET", + "returnType": "Promise", + "recursive": false + }, + { + "name": "getSat", + "parameters": [ + { + "name": "number", + "type": "number", + "description": "" + } + ], + "description": "Gets information about a specific satoshi by its number.", + "endpoint": "/sat/{number}", + "httpMethod": "GET", + "returnType": "Promise", + "recursive": false + }, + { + "name": "getTransaction", + "parameters": [ + { + "name": "txId", + "type": "string", + "description": "" + } + ], + "description": "Gets information about a specific transaction.", + "endpoint": "/tx/{txId}", + "httpMethod": "GET", + "returnType": "Promise", + "recursive": false + }, + { + "name": "getTransactionHex", + "parameters": [ + { + "name": "txid", + "type": "string", + "description": "" + } + ], + "description": "Gets hex transaction data.", + "endpoint": "/r/tx/{txid}", + "httpMethod": "GET", + "returnType": "Promise", + "recursive": true + }, + { + "name": "getServerStatus", + "parameters": [], + "description": "Gets the current server status and information.", + "endpoint": "/status", + "httpMethod": "GET", + "returnType": "Promise", + "recursive": false + } + ], + "exportedTypes": [ + { + "name": "AddressInfo", + "type": "object", + "description": "Comprehensive information about a Bitcoin address including its balance, outputs, inscriptions, and runes balances.", + "properties": [ + { + "name": "inscriptions", + "type": "string[] | null", + "description": "" + }, + { + "name": "outputs", + "type": "string[]", + "description": "" + }, + { + "name": "runes_balances", + "type": "string[][] | null", + "description": "" + }, + { + "name": "sat_balance", + "type": "number", + "description": "" + } + ], + "sourceFile": "address.ts" + }, + { + "name": "BlockInfo", + "type": "object", + "description": "Basic block information including inscriptions and runes.", + "properties": [ + { + "name": "best_height", + "type": "number", + "description": "" + }, + { + "name": "hash", + "type": "BlockHash", + "description": "" + }, + { + "name": "height", + "type": "number", + "description": "" + }, + { + "name": "inscriptions", + "type": "string[]", + "description": "" + }, + { + "name": "runes", + "type": "string[]", + "description": "" + }, + { + "name": "target", + "type": "string", + "description": "" + }, + { + "name": "transactions", + "type": "Transaction[]", + "description": "" + } + ], + "sourceFile": "block.ts" + }, + { + "name": "BlocksResponse", + "type": "object", + "description": "Paginated response containing a list of recent blocks and metadata.", + "properties": [ + { + "name": "blocks", + "type": "BlockHash[]", + "description": "" + }, + { + "name": "featured_blocks", + "type": "Record", + "description": "" + }, + { + "name": "last", + "type": "number", + "description": "" + } + ], + "sourceFile": "block.ts" + }, + { + "name": "BlockDetails", + "type": "object", + "description": "Detailed information about given block.", + "properties": [ + { + "name": "average_fee", + "type": "number", + "description": "" + }, + { + "name": "average_fee_rate", + "type": "number", + "description": "" + }, + { + "name": "bits", + "type": "number", + "description": "" + }, + { + "name": "chainwork", + "type": "string", + "description": "" + }, + { + "name": "confirmations", + "type": "number", + "description": "" + }, + { + "name": "difficulty", + "type": "number", + "description": "" + }, + { + "name": "feerate_percentiles", + "type": "number[]", + "description": "" + }, + { + "name": "hash", + "type": "BlockHash", + "description": "" + }, + { + "name": "height", + "type": "number", + "description": "" + }, + { + "name": "max_fee", + "type": "number", + "description": "" + }, + { + "name": "max_fee_rate", + "type": "number", + "description": "" + }, + { + "name": "max_tx_size", + "type": "number", + "description": "" + }, + { + "name": "median_fee", + "type": "number", + "description": "" + }, + { + "name": "median_time", + "type": "number | null", + "description": "" + }, + { + "name": "merkle_root", + "type": "string", + "description": "" + }, + { + "name": "min_fee", + "type": "number", + "description": "" + }, + { + "name": "min_fee_rate", + "type": "number", + "description": "" + }, + { + "name": "next_block", + "type": "BlockHash | null", + "description": "" + }, + { + "name": "nonce", + "type": "number", + "description": "" + }, + { + "name": "previous_block", + "type": "BlockHash | null", + "description": "" + }, + { + "name": "subsidy", + "type": "number", + "description": "" + }, + { + "name": "target", + "type": "string", + "description": "" + }, + { + "name": "timestamp", + "type": "number", + "description": "" + }, + { + "name": "total_fee", + "type": "number", + "description": "" + }, + { + "name": "total_size", + "type": "number", + "description": "" + }, + { + "name": "total_weight", + "type": "number", + "description": "" + }, + { + "name": "transaction_count", + "type": "number", + "description": "" + }, + { + "name": "version", + "type": "number", + "description": "" + } + ], + "sourceFile": "block.ts" + }, + { + "name": "CharmType", + "type": "enum", + "description": "Special characteristics or properties of a sat (e.g. \"cursed\", \"epic\", \"burned\").", + "values": [ + "burned", + "coin", + "cursed", + "epic", + "legendary", + "lost", + "mythic", + "nineball", + "palindrome", + "rare", + "reinscription", + "unbound", + "uncommon", + "vindicated" + ], + "sourceFile": "inscription.ts" + }, + { + "name": "InscriptionInfo", + "type": "object", + "description": "Comprehensive information about an inscription including its content type, genesis data, location and transfer history.", + "properties": [ + { + "name": "address", + "type": "string | null", + "description": "" + }, + { + "name": "charms", + "type": "CharmType[]", + "description": "" + }, + { + "name": "child_count", + "type": "number", + "description": "" + }, + { + "name": "children", + "type": "string[]", + "description": "" + }, + { + "name": "content_length", + "type": "number | null", + "description": "" + }, + { + "name": "content_type", + "type": "string | null", + "description": "" + }, + { + "name": "effective_content_type", + "type": "string | null", + "description": "" + }, + { + "name": "fee", + "type": "number", + "description": "" + }, + { + "name": "height", + "type": "number", + "description": "" + }, + { + "name": "id", + "type": "string", + "description": "" + }, + { + "name": "metaprotocol", + "type": "string | null", + "description": "" + }, + { + "name": "next", + "type": "string | null", + "description": "" + }, + { + "name": "number", + "type": "number", + "description": "" + }, + { + "name": "parents", + "type": "string[]", + "description": "" + }, + { + "name": "previous", + "type": "string | null", + "description": "" + }, + { + "name": "rune", + "type": "string | null", + "description": "" + }, + { + "name": "sat", + "type": "number | null", + "description": "" + }, + { + "name": "satpoint", + "type": "string", + "description": "" + }, + { + "name": "timestamp", + "type": "number", + "description": "" + }, + { + "name": "value", + "type": "number | null", + "description": "" + } + ], + "sourceFile": "inscription.ts" + }, + { + "name": "InscriptionRecursive", + "type": "object", + "description": "Comprehensive information about an inscription retrieved from recursive endpoint.", + "properties": [ + { + "name": "address", + "type": "string | null", + "description": "" + }, + { + "name": "charms", + "type": "CharmType[]", + "description": "" + }, + { + "name": "content_length", + "type": "number | null", + "description": "" + }, + { + "name": "content_type", + "type": "string | null", + "description": "" + }, + { + "name": "delegate", + "type": "string | null", + "description": "" + }, + { + "name": "fee", + "type": "number", + "description": "" + }, + { + "name": "height", + "type": "number", + "description": "" + }, + { + "name": "id", + "type": "string", + "description": "" + }, + { + "name": "number", + "type": "number", + "description": "" + }, + { + "name": "output", + "type": "string", + "description": "" + }, + { + "name": "sat", + "type": "number | null", + "description": "" + }, + { + "name": "satpoint", + "type": "string", + "description": "" + }, + { + "name": "timestamp", + "type": "number", + "description": "" + }, + { + "name": "value", + "type": "number | null", + "description": "" + } + ], + "sourceFile": "inscription.ts" + }, + { + "name": "InscriptionsResponse", + "type": "object", + "description": "Paginated response containing a list of inscriptions IDs.", + "properties": [ + { + "name": "ids", + "type": "string[]", + "description": "" + }, + { + "name": "more", + "type": "boolean", + "description": "" + }, + { + "name": "page_index", + "type": "number", + "description": "" + } + ], + "sourceFile": "inscription.ts" + }, + { + "name": "InscriptionsIDsResponse", + "type": "object", + "description": "Paginated response containing a list of inscription IDs", + "properties": [ + { + "name": "ids", + "type": "string[]", + "description": "" + }, + { + "name": "more", + "type": "boolean", + "description": "" + }, + { + "name": "page", + "type": "number", + "description": "" + } + ], + "sourceFile": "inscription.ts" + }, + { + "name": "ChildInfo", + "type": "object", + "description": "Child inscription info retrieved from recursive endpoint.", + "properties": [ + { + "name": "charms", + "type": "CharmType[]", + "description": "" + }, + { + "name": "fee", + "type": "number", + "description": "" + }, + { + "name": "height", + "type": "number", + "description": "" + }, + { + "name": "id", + "type": "string", + "description": "" + }, + { + "name": "number", + "type": "number", + "description": "" + }, + { + "name": "output", + "type": "string", + "description": "" + }, + { + "name": "sat", + "type": "number", + "description": "" + }, + { + "name": "satpoint", + "type": "string", + "description": "" + }, + { + "name": "timestamp", + "type": "number", + "description": "" + } + ], + "sourceFile": "inscription.ts" + }, + { + "name": "ChildrenInfoResponse", + "type": "object", + "description": "Paginated response containing child inscriptions detailed info.", + "properties": [ + { + "name": "children", + "type": "ChildInfo[]", + "description": "" + }, + { + "name": "more", + "type": "boolean", + "description": "" + }, + { + "name": "page", + "type": "number", + "description": "" + } + ], + "sourceFile": "inscription.ts" + }, + { + "name": "InscriptionID", + "type": "object", + "description": "Response containing a single inscription ID.", + "properties": [ + { + "name": "id", + "type": "string | null", + "description": "" + } + ], + "sourceFile": "inscription.ts" + }, + { + "name": "OutputType", + "type": "enum", + "description": "Type of UTXO output (e.g. \"plain\", \"inscription\", \"rune\").", + "values": [ + "any", + "cardinal", + "inscribed", + "runic" + ], + "sourceFile": "output.ts" + }, + { + "name": "OutputInfo", + "type": "object", + "description": "Detailed information about a UTXO including value, script type, and any inscriptions or runes it contains.", + "properties": [ + { + "name": "address", + "type": "string | null", + "description": "" + }, + { + "name": "indexed", + "type": "boolean", + "description": "" + }, + { + "name": "inscriptions", + "type": "string[] | null", + "description": "" + }, + { + "name": "outpoint", + "type": "string", + "description": "" + }, + { + "name": "runes", + "type": "Record | null", + "description": "" + }, + { + "name": "sat_ranges", + "type": "SatRange[] | null", + "description": "" + }, + { + "name": "script_pubkey", + "type": "string", + "description": "" + }, + { + "name": "spent", + "type": "boolean", + "description": "" + }, + { + "name": "transaction", + "type": "string", + "description": "" + }, + { + "name": "value", + "type": "number", + "description": "" + } + ], + "sourceFile": "output.ts" + }, + { + "name": "OutputAssets", + "type": "object", + "description": "Information about assets held by an UTXO.", + "properties": [ + { + "name": "inscriptions", + "type": "string[] | null", + "description": "" + }, + { + "name": "runes", + "type": "Record | null", + "description": "" + }, + { + "name": "sat_ranges", + "type": "SatRange[] | null", + "description": "" + }, + { + "name": "value", + "type": "number", + "description": "" + } + ], + "sourceFile": "output.ts" + }, + { + "name": "RuneBalance", + "type": "object", + "description": "Basic information about a rune held by an UTXO.", + "properties": [ + { + "name": "amount", + "type": "number", + "description": "" + }, + { + "name": "divisibility", + "type": "number", + "description": "" + }, + { + "name": "symbol", + "type": "string", + "description": "" + } + ], + "sourceFile": "rune.ts" + }, + { + "name": "RuneInfo", + "type": "object", + "description": "Basic information about a rune including its symbol and supply details.", + "properties": [ + { + "name": "block", + "type": "number", + "description": "" + }, + { + "name": "burned", + "type": "number", + "description": "" + }, + { + "name": "divisibility", + "type": "number", + "description": "" + }, + { + "name": "etching", + "type": "string", + "description": "" + }, + { + "name": "mints", + "type": "number", + "description": "" + }, + { + "name": "number", + "type": "number", + "description": "" + }, + { + "name": "premine", + "type": "number", + "description": "" + }, + { + "name": "spaced_rune", + "type": "string", + "description": "" + }, + { + "name": "symbol", + "type": "string | null", + "description": "" + }, + { + "name": "terms", + "type": "RuneTerms", + "description": "" + }, + { + "name": "timestamp", + "type": "number", + "description": "" + }, + { + "name": "turbo", + "type": "boolean", + "description": "" + } + ], + "sourceFile": "rune.ts" + }, + { + "name": "RuneResponse", + "type": "object", + "description": "Detailed rune information including minting status and parent.", + "properties": [ + { + "name": "entry", + "type": "RuneInfo", + "description": "" + }, + { + "name": "id", + "type": "string", + "description": "" + }, + { + "name": "mintable", + "type": "boolean", + "description": "" + }, + { + "name": "parent", + "type": "string | null", + "description": "" + } + ], + "sourceFile": "rune.ts" + }, + { + "name": "RunesResponse", + "type": "object", + "description": "Paginated response containing a list of runes and metadata.", + "properties": [ + { + "name": "entries", + "type": "[string, RuneInfo][]", + "description": "" + }, + { + "name": "more", + "type": "boolean", + "description": "" + }, + { + "name": "next", + "type": "number | null", + "description": "" + }, + { + "name": "prev", + "type": "number | null", + "description": "" + } + ], + "sourceFile": "rune.ts" + }, + { + "name": "RarityType", + "type": "enum", + "description": "Classification of sat rarity (e.g. \"common\", \"uncommon\", \"rare\", \"epic\", \"legendary\").", + "values": [ + "common", + "epic", + "legendary", + "mythic", + "rare", + "uncommon" + ], + "sourceFile": "sat.ts" + }, + { + "name": "SatInfo", + "type": "object", + "description": "Information about a specific satoshi including its number, timestamp, and rarity classification.", + "properties": [ + { + "name": "address", + "type": "string | null", + "description": "" + }, + { + "name": "block", + "type": "number", + "description": "" + }, + { + "name": "charms", + "type": "CharmType[]", + "description": "" + }, + { + "name": "cycle", + "type": "number", + "description": "" + }, + { + "name": "decimal", + "type": "string", + "description": "" + }, + { + "name": "degree", + "type": "string", + "description": "" + }, + { + "name": "epoch", + "type": "number", + "description": "" + }, + { + "name": "inscriptions", + "type": "string[]", + "description": "" + }, + { + "name": "name", + "type": "string", + "description": "" + }, + { + "name": "number", + "type": "number", + "description": "" + }, + { + "name": "offset", + "type": "number", + "description": "" + }, + { + "name": "percentile", + "type": "string", + "description": "" + }, + { + "name": "period", + "type": "number", + "description": "" + }, + { + "name": "rarity", + "type": "RarityType", + "description": "" + }, + { + "name": "satpoint", + "type": "string | null", + "description": "" + }, + { + "name": "timestamp", + "type": "number", + "description": "" + } + ], + "sourceFile": "sat.ts" + }, + { + "name": "ServerStatus", + "type": "object", + "description": "Current status information about the ordinals server including version, height and indexing progress.", + "properties": [ + { + "name": "address_index", + "type": "boolean", + "description": "" + }, + { + "name": "blessed_inscriptions", + "type": "number", + "description": "" + }, + { + "name": "chain", + "type": "string", + "description": "" + }, + { + "name": "cursed_inscriptions", + "type": "number", + "description": "" + }, + { + "name": "height", + "type": "number", + "description": "" + }, + { + "name": "initial_sync_time", + "type": "Time", + "description": "" + }, + { + "name": "inscriptions", + "type": "number", + "description": "" + }, + { + "name": "lost_sats", + "type": "number", + "description": "" + }, + { + "name": "minimum_rune_for_next_block", + "type": "string | null", + "description": "" + }, + { + "name": "rune_index", + "type": "boolean", + "description": "" + }, + { + "name": "runes", + "type": "number", + "description": "" + }, + { + "name": "sat_index", + "type": "boolean", + "description": "" + }, + { + "name": "started", + "type": "string", + "description": "" + }, + { + "name": "transaction_index", + "type": "boolean", + "description": "" + }, + { + "name": "unrecoverably_reorged", + "type": "boolean", + "description": "" + }, + { + "name": "uptime", + "type": "Time", + "description": "" + } + ], + "sourceFile": "status.ts" + }, + { + "name": "Input", + "type": "object", + "description": "Transaction input containing previous output reference and witness data.", + "properties": [ + { + "name": "previous_output", + "type": "string", + "description": "" + }, + { + "name": "script_sig", + "type": "string", + "description": "" + }, + { + "name": "sequence", + "type": "number", + "description": "" + }, + { + "name": "witness", + "type": "string[]", + "description": "" + } + ], + "sourceFile": "transaction.ts" + }, + { + "name": "Output", + "type": "object", + "description": "Transaction output containing value and script pubkey.", + "properties": [ + { + "name": "script_pubkey", + "type": "string", + "description": "" + }, + { + "name": "value", + "type": "number", + "description": "" + } + ], + "sourceFile": "transaction.ts" + }, + { + "name": "Transaction", + "type": "object", + "description": "Bitcoin transaction data including version, locktime, inputs and outputs.", + "properties": [ + { + "name": "input", + "type": "Input[]", + "description": "" + }, + { + "name": "lock_time", + "type": "number", + "description": "" + }, + { + "name": "output", + "type": "Output[]", + "description": "" + }, + { + "name": "version", + "type": "number", + "description": "" + } + ], + "sourceFile": "transaction.ts" + }, + { + "name": "TransactionInfo", + "type": "object", + "description": "Extended transaction information including block details, timestamp and inscription data.", + "properties": [ + { + "name": "chain", + "type": "string", + "description": "" + }, + { + "name": "etching", + "type": "string | null", + "description": "" + }, + { + "name": "inscription_count", + "type": "number", + "description": "" + }, + { + "name": "transaction", + "type": "Transaction", + "description": "" + }, + { + "name": "txid", + "type": "string", + "description": "" + } + ], + "sourceFile": "transaction.ts" + } + ] +} \ No newline at end of file diff --git a/docs/favicon.ico b/docs/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..bc882e6ebebf2c39678cb2a014e2a7477562fb94 GIT binary patch literal 13375 zcmaia1yo$ivi2Ye1a}Dz!F6zVch|ukf(<0NJ40}{5Zv9J1h<3)hXe@{AOs6;|K`ZO z=iPVT`uAEhyJxzpy1MtS?y9dUT3uBR9pyO+2n0e`keAj3f#85990>U-aDzb0Y#x8P zYsyK2YNkkcfgeNG`U*BGDj+7HjSPAUhXX=*Bza_mdk%W?M;ipvg(LY_+XRl`FB*7& z1`GneLHNMOCej{+_!qq&aDQyFJbwLsSGV`Fe(7ZH;R2;phq_R5vGK6+0R4ywh=0hy z1KJJwaQ_}ZAO3H7aG-pIf42cT5GMyGw;%^t5DcaS^9u6t3-a)QPRcP9fv#t+@&@i8 z5F5?o2hOWl>@^64&}6Tz@1d`vENJQC#Aa^gVqwkZ<>dM(2_)<#2sE9nJ*Rwr>6Xa#KTd9T3fI;o&OC&hF{y$>zz$<^r{42MY)Yuyb&-b8@l*6s+#v&K~Aotj_Kn2h07}s5o+qkf&O*Tyzy#SJd)UEj9PIy%&DzWU z|6qIU`9Il!HTu`I{>NZm=B|G-{jnH->L~oEfuMn=wY$s9SC4ZM<>L6`Vh2Cog#Xa+ zfAs%*et+`n|9^P@+5exs|7O*3w)YU_{A;-X`1?P()S&j(z%%(nTku~j|NQSC^p6WA z_{ZyPAZ_nt?d<+ILrxxEVfO#p^Itjj|4+_;^!$SpSbsqk;BB-r_b`_>_playGyzr) zFe@0W4dxRB3kdRXvU2bXKCbTnqWup!Qc!C^!vB);mm&RA%0DRon+zAIwu{S4(f?-I ze`@gu|6f#p2@qy~e6RoUp8sh?fBXwrkthnl`L{)iqEH;U0hGDwinz%E^3wb z?AZgR+LP1^sf3XyjPGK&b(&Nz<=A+lqGS;ZrxBwI#2m8T(v=+Vu-h{^oJDGIhc9Hj zZ81#dt=G2v1UgZ7`EYk7$(U~ueA0mLjVj7^xpq6h!|$H!+s<_{F=2RUtD0JTs;D>99*W zi6-@nWFULbJAEO|7v)TFCp)7QgMCCMejW0G{mg6nZB)|H4@{Y>t*Ine*?NVPDUiRG zM>T^jfr(~F&><)Zb3ok9TrxP1{ZK%sR%TuEJK6LQ{8v2~`lMpEAJUqr=GV=H2Q?1| zRe|Eek@vJ88ggn9=WB&HiE5UA34!>cFjGH3s1!e&viMY#rQ>2>LPQN&6(f%dehe3w z2*YPeo7H*Up-%TklM|wMr-j311d|bk6cfga?_vL-C!fOim-%g^@%FbMQ4noL2rH5A zF>(<~u+Q|*1(=3Aa{2thzOgRojkY#`v*0FGnVy>Y_;2$=He4k zWZ>T$*bJz_QwuYBy znb2#*w*lAotncNrP4Mq9r>k$jU>6m7fKp~Uq&)KMFsCOJ7Tfxjf9-vhSZPIJEh6vA{MDMe6H|f57RMYchH%jkA(ydU1Vy zZMHEGt?}8^wg1Uv>F%=*o!NKoIbJsht%Xzh@7_^)9W>8}l+XoOaZzd0cNqPanEsx5 zv>-%GzjzdFW}1WdaFR@ZEgQe-cmSi3mX&ZB*nYcVm{( zZOo7&>|u^^j;>QmC|DUxqNI2#=o^0Jr(>IXpcXS0uo~>W2*3Wg+Lt2l-Q>KD&!`2_xDt7@a-|iV zSVK|g-(ET*_GOKSI)Ck;C4V4ATBpwWy#WgDhsL(b;Gzf2*BE~gaNiE&q^{u+yL*Vk z0{L2qvm|Xx#U;Cbfl4KyE+FrKw(13?9Y)YGfI3l_k z>^_6G{bCfvd#xT{$c#5uZSVcH>*2TVXI~a5dJGW(b5#zJ68QDroE@LiHQjI6du>Yi zbi#G_bMfrSRG^qOGM1J_He%^!hU=mdG4cxYjUc*iscP=~W#>-T+nK`OD{drPXGQ8AitET-PrfG8Z*(4H! zEN0AqODX6$M*TU9DRu0H|IIo2N$~&!t88?Af2iXQ_Ql?8WhjYr8`b6I_jnb{PZ7rt zX&<*+kG(A@imMUUeC*#TaobE}U<)4);KK2oHqb?4Qef~puPi{~U^vDhAPL?J^?%G7CQ#!BwJd zM{&I^Q1DZQ+(u@3qny8{9(#)E)Qr2w-SydeD5fZpY8E$Rim90%V)ZruWz5G*Rg%wa zu5haSKM~hDDCiUR5d-LIr=DIx+y?Q>b4$h>_pQg%!ueMH+`Wc~ZQEWH?bh3&Iu$tC zlWFxgS+=d$;Rc<$_DZ3CFUdtaw9dKgzW7E$E*2oHBPOq@zz1oES~JWSzFTp1SLlc03)GtG8I^^bSi#BObtIY9MiB6OT2AAt67j7{_V;fl zFYSeB`}(L=;Pps#si~11cCcaGbaB5^a&we-Q-}55r4*~8_Y#$gIxTUh_i{$lcMNnC zVcu?pC}eFL^%1vy$vaeB9(@8WkV1|p&&4}6laznHy+3|>ezaTq7GoL(am2SZ9Qdo)x&Z4`x&4MH>~PIG$R(KoXN?nC?8 z$Dt4`{m9Ywc_Pgx+&cdNnWVf{pI)dI`a<@>{6R}gb1_D%?0>2 z#L}?NIYsB0m+z(%Kl7jNb$=;UQ~Ukf?RaDGU2IAtonmAoW{FvLimL*AE2#(kCUU!` z)@LchQ%?;oQ095&jQjSh{ke8w9qz$tLDkuX9S_o~WURI=I|p#P8Fe@vVmNi&m zqn#5$etRl+|8S3FxHUmcmH0-{bM+%)>MkW;kE6oVN(f6vstS$ z1em2UpnY<^%6V(H>a$;Mb5K7}L9<9F%NB^YmLJ+Lxv5#QDSSNlGJ-;i+c@sXa?t@v z;yf4j8S`m9v>i`1uN#42xyOt3ugr^4VWx3=NWU}#z9FYa{)ye}j)#Q3zdHp*`4+7S61$^Bk(1kl6x_ z;7z2BLEnO}mFFd?a0CYl_1~&RXYX2pqc?$PEA*q-17zM+a&B|VvneQ27}dpOK+56p z$;tS9*AgboZ&MH9y-KDdMK#e3aCOCe>hZq`G46aVgZid!Au2~u4mD2x^NShIuOIS! z_R9N}*t_wRbNDspU6~!ZY^RzG{leI2`dl|dLJX#!6dPvcx8TI?E4}uzJ`Hdl!#jf=HN_@8+uMeK9<_hvKrR{Fm%NH+vCwU@rjQ^Ik z&Dmd2`qZ7#m(Q6IuoX@~9- z99}^DZac7}vUn9Z;i~G#;Rbz)a1>8~sfO=HuUu+j{`y?3gz8;%oi}Y}K(wi4YDzJN z&P0#!RvXUw0}+BHu(39*!Aexx%mpm4oE@)?%wP}?LF>zokkCq=7)>SJ_g+U$n1|Mg zi%ZRp)s*rpY))L{w0b;*>rq=Pa37!+n?<<0)N)smcC%)LOF!moP1`&VO}LUc8Hs2AfeK>pnow1vqepJQ1T_P_3TaXNlz`&fG zlXd2Z?d70;EV+oFpa`#{*BH9HJ?JTcU&Rm|q&`OxZNBojcEA(hT4az@cLF^jt%~u{ zB%*dYy|SiMlD9aX6rPYx4CFbL_u`YZ3hY*G$*ro#>2YMBo)TxdmU@q=~AL) z=?D_)Pb#>Z3$498RuY?vhu6%ZX&ZYHl%S2!&r?!WkmxRw=8RK>gU zqFo6?k3}rqg@87Ic3HPd|6SbIjX{`>KTD}GdFDSU+?(ieO| z8_7&C8!kHZhNSe30e4=&KomAXU$f(vGr{n^HS3l9(6h@JC};{CFJUx-J*o?M{0Z{q z)bOP+8eHaIf=ibh9|KKvY-b_{DK9@z++*p~IJp_xJh|mW@N>0HO*t5Oy3_=u8`L= z(7!gk0lf7x#?7ey3?yj#%d2cZDRh09Tp%hToAzmKP79~>tWpP-yu$(q=?p=rT*xNW zfK&Til&vDo%yF(tV{mt&-g5oZJE_@Q*s?BN`DOiG#XD`Vta4I@I3m(|K}iC$+ZBU*q;M8eu@Kl3LUbtIYgJEN zkQlDcesGf#GqJ7~{%d(Fhan(p%@Y9pqb z%ffh3lr(lzlf`uA+qtivt7Ngyc`Dw!+|;(q2I*sSrNh%doYe-FlWPij4z%mHR~w$` z-K4vJ>+)6&ykj(S0&ghY%)eiDj0S<-jiIE@4k+z33YF!XuN8XCa4X{A?wxFsmR}YQqRd`cWI{2na45ES77kS8uoZ4t{<2 zl;?x5u`HX^*vH6!_4{5;R9(PngYBi3R`OCiO=bD-!&TG4R(_`@NUbfpjQ7QH=~ZVq@fWZ5O&=;8YE!@N6EIUc3> zOJj7jkVaQMC2n^`KkE6>E6P5bdDpIn=Fq zv}0F(NF0*mb?4<{z#-lYVYc7-ti;aR{?(<53=uMDnB6(nj{m4b*%y?-7_+ z;lx*~2<7i9EXGL`#NY?AGCHwTFycvxbDJI8Ri-ZT5r}H6v4yh8f><)Eb`3R*#y;x9 z$cJ6zG2v@0YDUc`SH@&4_{oC4skIPQR#uKL*4%FaNK)-Lc{J3T5v&jRy)YU;T}bkW ztoGDUZ$z@7rFL}y{est4(hr&rf5ed3FuunpQvXS`bVa*PB#HFNl$mWwB!$jvaA}0- z7{Fj!7i=E9-%yKB7*AY%+OC7fos}XG<>Ol(kT45*{+fYSm*oPpM=H&IZ8&`pAms#5 zMt3*cx$6rIKP}6HlNWfwBP@2ciAygPl!~NR*1Ss6AlE1JlNhJV_9J=okll6$f3fdV z4zr-8QE73cHA%EzRUNL&6jE?-diAT_zO5mxtC^oB!1Wp5xIlVm50FIhH*nt)o&#%8 zJ8BK%3JNfcayVDLxj3AMRu+*F&Ii+y9g*Nli4&Z-LSIf|h;t1W9s9Q<-dD^QoEpZN#e}HD_|~bkn8txGSswtO5853=?LJ zUlpvx;cro+9*|DDsN(*qEii(Val38#O|`~!o(0i8H@LtN zZ}b#={WAl1$nN^*fO#Mm5AbwMlE=qHvqEA^|;;%3S! zwUxo#;48ubmTZ2r!6r^Yy{7;{U1)v|QTs}}lmRXkj@5^>m&*TNic&+B&(Orb2uzwZ z;+;XN1=PoodRdA894bqIu53RK&hES{D?ha$y%IaJ*zagLNuuwsRS4<$MI2P(J|;yD z<5YIfu$d0ML@$^AyB8xWec~RyuVZ9d&dqJxSM1L(Wg#p~XxWh-#Q%v%z?&l8K(l=|Nm`k@Sf%-SdZBZh) zacd1}`W_$$TToW>N6>^!GkHY|xd2p}S@fH#EEeVV629-ULkDkUsyj;uqIxG%o#k*` z3rE={7a`B`dk(a3zK7j0{=ZEp=->x(7K~tj6EYiI14zZwvNXF;y@}e^Z$6a^bdM&p z#B+>C%a)i(ms^}*_(A+a?S_rL^%`}?KAmihD>!L>Bk|oKQ8mA=}ZY73e!u4L~j5fx)FB< zu(MFEF%6-?MRXb#WNHb#Ey(%k3CiA*YF-L*>Ah>w?R*4bpNQSKxe zn#fto7FE{)A~t2qz(Tm4yRP>Nd^@}&Xm0FjvrfqK=g+kbINi6Eb$p9sk8|{|QYvTGZ+R^dqlznSAGl?*E63WU z!iTi#Yy5tLAz)5*HhZVI7g073j8f4II4XE&U|!k)V1Qu4T3V8Xf5@9#nq3 zH-`+`WnlOgu1+~_sVitQn-9sT<)yu-ezS|9=P%NUOs-NxE^GgXIH6z2n^`qghnKm@ zazPo`Lh0~)>t$&i_isrx@t~c9n)*)Om4e^^0NjhYN9tGM`&xto^_{{Fk|Xyn>i&9r zoMJt14tA9=1)aVdc2gWbbf4XwU3vzNIYN zP4+Dx9ezOZYRbFQFEn{c^4Gw+E%8ml@&O7LktnW?&?Vr{YS(*TZKcop!Iq~KlIg;S z<0M^#NOI8(Rg!Be<`xtdekRe8)gJVe4s_)hw0~W*kt)B^B>aELudPB4)pJh^4#UxH7 zpa39z#kT26OP>Gv;yM6>*DMjZRQVtRX^LnPIe?WCGJ^+|`Qy1{=7>rFVTM_0yo?V0 znHT`M)01{(VRm>PlCQj)H=fNX`_VaL{iSEwD3Rt~i4}{IZj9&DaDn|ClQawlIQGmN zB<;$o>9oBG-LpOgc_O|M4NZwQa>V5S2>bMG(#u;0Nh(Q$BguUjurd1ni2DF27K708 zrxIH_Yv>lqDi8yoE?CCfTi`GH+#V0l-ZGa~pRDkuz$fn=96ueG3L?USK`ly~*;l?0 zK&AiCJp)oBZ<6RzE?@MrHPEM%rlEu-_ zx1=@t+Hapm5k97kn!u>mP3BekZhlT=+;-|^B2yA%`OmqLw-JyqwBv0d0eu2aRD2uc zy|H&=9XIT+jpW6yY8A96>lw95?7kB$cK#@U&G@mjc5A{jrMy~JUfOz-7X{J}^=^0j zyhKrB5EV=N$r<-CZl?`Qa;X%gEj_&*A-J=$JiCNVBu6LJq2}Sc zr)?#y|H1_f_Xa~M+#78_&JD3Q@Ol1%=!lIw@%1X+L;GGdC2G{EoTO8T_JL8U=*PB< zV(<2?De%oz3$j8_R=8K{Eh7cvge8eNt)jBtrZ#2z!ru?&``FPaCwFZ}qPi;GXz zqBcZD@w({jV6Pe|aHd?xP2|qmM(g|iYTs!JW?3fpEV-kR>^=&y*7UqV6+mlc34<^Q z$9?vN>Z&}AF0PfHB~9(He}^Yr*T>bhS5Y~0Th%lPVZQE{oQ)(zOZJ&ECGzFBrrHFx zt9!A8Uu-f7R5E>x;?a?_oy@Whwr>Nxd1(r4{EZhp8@DULC0d>p+oaGk~pOKCb z{HB7t+608B2h@7ATXGf}vx`6|knxqhObPo=$&nO>+|Y#=OZ7nlF7n3OP8&%h<;nm z`n(C+I@(G-R-3a&w3Kt!I64&ZEX=UUF7e4+;v`_8qCaQKlRG}nZir7_#C81wIq{YG zn!d_eN6D$jX)|H0K}mkj3e3=*1o;Bu|BDT2yfse9I_SN+;MTzP^XC_aFm%VC}C)UW~J| zv*}_9))cBz^qjpfbWS-<2mR>$z{p0+J2@iIdVO!PMJpPv!786nebWQLJ!p)P;Lf)M za(8Y1;1%g;Wy`5K#E##TJK2PEO6g_AqSza zAYTLWlaoc2i(VE5t zot8FGgs^9aXl!X|>9sk6{VM0=Y5gRasCpQjoabYVmfZFh*O%Xn(RIP~4h34vG|m6& zGT5t61^Mg74+~cSoeEa&uc`<>@Na+2CQxMtD~sB@%qzc4H_Z~Su|*)Z!;xPflfMe= z3xZ2LKU@_{kl+hOYjvuzWe;_OH&~&zb8tWjtLwkNy9otyu1`8&AE30jtdcYGTzLLk zA(n5jf{#4UN!i5Q+_vIy+ZZ^1UF~oKoV^IdTI#89s7-B#R`sV@Wm<&pE~x~vM%j0h z)kN(VCFEMJ@JBYbg7CMSozwM=9!{iK+8m>31=64I(&qid)^RyvEX~1jUTK@|!d(;O z*p1;Lxb)6u6;Oz+uDzmS&I#|7y-ar8gj8(G9uF1u7s|eYLNBs~`h_tX93opCKg74S z;TY|A-n|f0lUjQT>1A4ohbR@7vAv*XefcyI+luY!&=CtiYG^o0{qbS%jsln^s(i~m z0EZ&DaHx>1((s4W5ja)D;!bILdtlZt@UZ(LAhO}uR5rBOf1!@9rr8;$Zy0yPTtq|4 zGm!k4V*;$nla5kdWKgGGWhj)3ap35x`kAcmg6%Y0JxxTKO8D#?J@_#ws%8@^HgzXU-y%Q!k&N3T=Llm*Jv)VEvXA zESZ2wCa6t>^yMNYLQ(6Dgwo5#m)S%HsmBg5GuKc3@d)iH0_Hvzp=Ad2ebjH*Leb&M zu=a;h7Y3U&d$4dT_qv^EMc?*|Ai+K-NllerkAZbImFuDMGgY`|&E~{IhAgslZ@Ff9 z&|&fV8(Fl=10fl0c>G8gv2N6!Bkz>Qn>V@{)q(UWA2X9-j5Z5?>e(~!Tz!2L=DF_p ztJD}F8IkoI>t$%mXl_s@gwu))ub<6#QSNOTgLB~?e#FJ=^I{W!|WIBlD25fl(AzLCVNG*hMh z3EWUEne^|7OVm3+LClA6R6;}DF!1oSOx2R$Qyq^!476lC{>`J$aVursyDwP%BxZ8D z&^`g%{O9+(G=rQUMJ^zxyq$fsCqzK5Tft;#>k8hJ6zycxJtT*cPcZCvif#{UmP^+n zvlKURX)b}e#>hBZ=Y$v!LzIZ;S^t1T;)0?DrfqEG1pzb%QRc;s{|l6;(G0M7xm`TS$R1`8QmZkyhxD z1e~_U9vkBM_5bB@0iH@o)}N z@!;WKl@a}I5vKe4{byOk+ssZHiP-~VZqsvSnYU_#x`edD%_AS(kN#DWu}@pH_YH3T zA+*y|LB4^9nk8s%gVXC)&f@#RCDJBoD55gv!5VX=E~+vNt#n0)THz9t->_$l+< z5mTrkJh49R2)jqoNtMV6Rj*<~)d69S-^r-NYL7pHE|vukm5G|z-EVmnve$NgXM3~# zKNlNA10QZyG2)+-#k?m!HKyQ(4R`A0IPd=+{mF$Q-w;x{^?7qEFYo&9)ni=C|4y>@ z!U~L?{5z8it}%?=CVPJoIF0u>KN=|knFz&~u)(jF?rlGd;St;D*M1J=lU8O@D&MSh zdb(^3oMC83g1{c!;jNiMPlQ7{T^E$_kzI#p7HK2}bloYphRhy|jAleTYuI=kZkA*D zC|?iMag<=JepsAYIUqFUWEJLm#j7tLHygsOjI8j5|7=P1>zwiB`a`(JKSsp ze7dkkn@N;b=dTWu7A{SGh*3|#Zu}9wMDuGlkrd19L>WLv@Rt=+J!z?a{)ZalPTB9v zU({XlZ&S+OxCDu~qeaP->kBMBrC%>0L_+?ZV#&|QL_N%?z(y>LJC>iMF8h5}R@XWo zAJ~!1R!#g!og!hbpJ7snM1z-()6#iZBW`Mx6tBJm*|fx9ys;9P*?t-C>a%($=5GSO z`un-#%J5qSBh;m*yO!!mY1kMgiD@YAe|h#Q9W;GsDHi+U0cySypqZD2n zN!gh6$2vEKGNupZds#e=4Jq#BNB9$cQ|8ur&^CnmwVZT3s!vjW-il2*;)2Vb6B*!j zk&Bh@9*cY0R#0Nqx*|TJU>(En8Q+N@r%9TKL_vu^yx;@^6yV(jeIM>FB7v}(kw(P9 zeIAIR<@Ae=@OodNt*20|B!4b)Ihe~lkqEWhr!4vP@IQ+DwvXm*(g>Skct7hdDK9r- z6_Tc}X-_J!u6F-qnZ9P9_Lc6mrh?*qEvv1?q*KiyQqJI@YFi6Ih2P$@H7FCHq-_Zu z8XEe$x^M=TO0;p>ywLMUabd);!h{E_C&*j+<@S`gYBEB( zG2w{afHtp0#qCp0CiV*T6t!!>-;^Dc)7*8nFP$6R&X!qa?KWy@eI14og!~G>`>`go z#AVGjjS|tvK=Txza>^ytS1N(455;WXkyrvv1cFia}!8pe@G21 zzDq&=t}XH~<~tU7u-e-zqfif^Z*tLUNa}?r6;1nM(yeoLH-3#!45?uMkXOoRQ6i*4sE?JdVhOL=vCneFhu;Tf;Q9hZw#dPw zC+R}HJv3!NEiJhId;^;w4$e7d3eR6{#uKp_D3PTFz$=(s{tI|C>JHW46a_srBfL)s z67+Gj0QLqfvw=zU0umX2xdfo>mbhMNr;O2ULa7BSgZftu-Wi!h2bfZJU<@YLhZsx| zJ!>nC%dEvVe4eYWga+6Y6)#Y_tBOU$BG<0v(O9N7V#NW}Hgd?%0Cl=x#J#PNKpYXK zJs|`mv_7J$eVJ}AM9pw5GouS9B-|FTeOWdG_UPqly` zeE8L26feP#9>bS*x=WivLBD18tlaFoeyB+gZ~cxu$!gvR8XnkDDIkGfmvq(OZ?W~H zr%9c;LH>eFnk`*k=v_?Y})jprb_G~LTD3EZm z_8^RSTvG4&j;yW&3{uiJFbuo1CB6HdiI7HQHug`qzTPBn95xBFwLDTTZZ#=zL?}CY oXZM}2-iEC*F1^^JEkwQz+*Ca5T>b%I*TAJ9qbgk^X%_PT0AV2Ju>b%7 literal 0 HcmV?d00001 diff --git a/docs/generateHtml.ts b/docs/generateHtml.ts index d7d525f..db1395e 100644 --- a/docs/generateHtml.ts +++ b/docs/generateHtml.ts @@ -1,213 +1,226 @@ import fs from 'fs'; import path from 'path'; -function escapeHtml(text) { - return text - .replace(//g, '>'); - } +function generateHtml() { + const config = { + repoAddress: 'https://github.com/raphjaph/ordapi', + version: 'v0.0.3' + }; + const scriptsContent = fs.readFileSync('docs/scripts.js', 'utf-8'); + const apiDocs = JSON.parse(fs.readFileSync('docs/api-docs.json', 'utf-8')); + const cssContent = fs.readFileSync('docs/styles.css', 'utf-8'); + const typeNames = new Set(apiDocs.exportedTypes.map(type => type.name)); - function generateMethodCard(method) { - const parameters = method.parameters?.length > 0 - ? ` -
-
-

Parameters

-
- ${method.parameters.map(param => ` -
-
- ${param.name} - ${escapeHtml(param.type)} -
- ${param.description ? `

${param.description}

` : ''} -
- `).join('')} -
-
-
- ` - : ''; - - return ` -
-
-
-

- ${method.name} -

- → ${escapeHtml(method.returnType)} -
- ${method.description ? `

${method.description}

` : ''} -
- - ${method.httpMethod} - - ${method.endpoint} -
-
- ${parameters} -
- `; + function createTypeLink(type) { + const escaped = type.replace(//g, '>'); + let result = escaped; + const typeMatches = [...type.matchAll(/[A-Z][a-zA-Z0-9]*/g)]; + + for (let i = typeMatches.length - 1; i >= 0; i--) { + const match = typeMatches[i]; + const typeName = match[0]; + if (typeNames.has(typeName)) { + const startPos = result.indexOf(typeName, match.index); + if (startPos !== -1) { + result = + result.slice(0, startPos) + + `${typeName}` + + result.slice(startPos + typeName.length); + } + } + } + return result; } -function generateTypeCard(type) { - const propertiesSection = type.properties ? ` -
-

Properties

-
- ${type.properties.map(prop => ` -
-
- ${prop.name} - ${prop.type} -
- ${prop.description ? `

${prop.description}

` : ''} -
- `).join('')} -
-
- ` : ''; - - const valuesSection = type.values ? ` -
-

Values

-
- - ${type.values.join(' | ')} - -
-
- ` : ''; - - return ` -
-
-

- ${type.name} -

- ${type.description ? `

${type.description}

` : - `

Type defined in ${type.sourceFile}

`} -
- ${propertiesSection} - ${valuesSection} -
- `; -} - -function generateHtml() { - const apiDocs = JSON.parse(fs.readFileSync('docs/api-docs.json', 'utf-8')); - const htmlTemplate = ` OrdAPI Documentation + + - -
-
-
-
-
-

OrdAPI v0.0.3

-

Simple TypeScript client for ord API.

-
-
- - - -
+ +
+
-
-
- -
-
- ${apiDocs.classMethods.map(generateMethodCard).join('')} -
- -
- - +
+
+ ${apiDocs.exportedTypes.map(type => ` +
+
+

${type.name}

+

+ ${type.description || `Type defined in ${type.sourceFile}`} +

+
+ ${type.properties ? ` + +
+ ${type.properties.map(prop => ` +
+
+ ${prop.name} + ${createTypeLink(prop.type)} +
+ ${prop.description ? `

${prop.description}

` : ''} +
+ `).join('')} +
+ ` : ''} + ${type.values ? ` + +
+
+ + ${type.values.join(' | ')} + +
+
+ ` : ''} +
+ `).join('')} +
+
+ +
+
+ `; - // Create dist directory if it doesn't exist const distDir = path.join(process.cwd(), 'docs/dist'); if (!fs.existsSync(distDir)) { fs.mkdirSync(distDir, { recursive: true }); } + fs.copyFileSync( + path.join(process.cwd(), 'docs/favicon.ico'), + path.join(distDir, 'favicon.ico') + ); - // Write the HTML file fs.writeFileSync( path.join(distDir, 'index.html'), htmlTemplate ); + fs.writeFileSync( + path.join(distDir, 'styles.css'), + cssContent + ); + + fs.writeFileSync(path.join(distDir, 'scripts.js'), scriptsContent); + console.log('Documentation HTML generated successfully!'); } -generateHtml(); +generateHtml(); \ No newline at end of file diff --git a/docs/generateMethodsDocs.ts b/docs/generateMethodsDocs.ts index 885b547..951b520 100644 --- a/docs/generateMethodsDocs.ts +++ b/docs/generateMethodsDocs.ts @@ -1,149 +1,82 @@ import * as ts from 'typescript'; +import { extractDocComment, parseDocComment } from './utils/doc-parser'; +import api from '../src/api'; -/** - * Represents a method parameter documentation - */ -interface ParameterDoc { - name: string; - type: string; - description: string; -} - -/** - * Represents a method documentation - */ export interface MethodDoc { name: string; - parameters: ParameterDoc[]; + parameters: { + name: string; + type: string; + description: string; + }[]; description: string; endpoint: string; httpMethod: 'GET' | 'POST'; returnType: string; - responseSchema: string; + recursive: boolean; } -/** - * Map of method names to their corresponding API endpoints - */ -const API_MAP = { - getAddressInfo: '/address/{address}', - getBlock: '/block/{heightOrHash}', - getBlockCount: '/blockcount', - getBlockHashByHeight: '/blockhash/{height}', - getLatestBlockHash: '/blockhash', - getLatestBlockHeight: '/blockheight', - getLatestBlocks: '/blocks', - getLatestBlockTime: '/blocktime', - getInscription: '/inscription/{id}', - getInscriptionChild: '/inscription/{id}/{child}', - getLatestInscriptions: '/inscriptions', - getInscriptionsByPage: '/inscriptions/{page}', - getInscriptionsByBlock: '/inscriptions/block/{height}', - getInscriptionsByIds: '/inscriptions', - getOutput: '/output/{outpoint}', - getOutputs: '/outputs', - getOutputsByAddress: '/outputs/{address}?type={type}', - getRune: '/rune/{name}', - getLatestRunes: '/runes', - getRunesByPage: '/runes/{page}', - getSat: '/sat/{number}', - getTransaction: '/tx/{txId}', - getServerStatus: '/status' -}; - -interface ParsedJSDoc { - description: string; - params: Record; - returns?: string; - } - - function parseJSDocComment(comment: string): ParsedJSDoc { - const lines = comment - .replace(/\/\*\*|\*\/|\*/g, '') - .split('\n') - .map(line => line.trim()) - .filter(Boolean); - - const result: ParsedJSDoc = { - description: '', - params: {}, - }; +export function getMethodDocs(node: ts.MethodDeclaration, sourceFile: ts.SourceFile): MethodDoc | null { + const nameIdentifier = node.name as ts.Identifier; + const name = nameIdentifier.escapedText.toString(); - let currentSection = 'description'; + if (!name || name.startsWith('_') || ['fetch', 'fetchPost'].includes(name)) { + return null; + } + + const comment = extractDocComment(node, sourceFile); + const docInfo = parseDocComment(comment); + + const endpoint = (() => { + const pathFunction = api[name]; + if (!pathFunction) return ''; + + if (typeof pathFunction === 'string') { + return pathFunction; + } + + const params = node.parameters.map(p => + (p.name as ts.Identifier).escapedText.toString() + ); - for (const line of lines) { - if (line.startsWith('@param')) { - // Format: @param {type} name - description - const paramMatch = line.match(/@param\s+\{([^}]+)\}\s+(\w+)\s*-?\s*(.*)/); - if (paramMatch) { - const [, , name, description] = paramMatch; - result.params[name] = description; - } - } else if (line.startsWith('@returns')) { - // Format: @returns {type} description - const returnsMatch = line.match(/@returns\s+\{([^}]+)\}\s+(.*)/); - if (returnsMatch) { - const [, , description] = returnsMatch; - result.returns = description; - } - } else if (!line.startsWith('@')) { - if (currentSection === 'description') { - result.description += (result.description ? '\n' : '') + line; - } - } + const functionStr = pathFunction.toString(); + const urlMatch = functionStr.match(/['"`](.*?)['"`]/); + if (urlMatch) { + let url = urlMatch[1]; + params.forEach(param => { + url = url.replace( + new RegExp(`\\$\\{${param}\\}`, 'g'), + `{${param}}` + ); + }); + return url; } - - return result; - } - - function extractJSDocComment(node: ts.Node, sourceFile: ts.SourceFile): string { - const ranges = ts.getLeadingCommentRanges(sourceFile.text, node.pos); - if (!ranges || ranges.length === 0) return ''; - const commentRange = ranges[ranges.length - 1]; - return sourceFile.text.substring(commentRange.pos, commentRange.end); - } - - export function getMethodDocs(node: ts.MethodDeclaration, sourceFile: ts.SourceFile): MethodDoc | null { - const nameIdentifier = node.name as ts.Identifier; - const name = nameIdentifier.escapedText.toString(); - if (!name || name.startsWith('_') || ['fetch', 'fetchPost'].includes(name)) return null; - - const jsDoc = parseJSDocComment(extractJSDocComment(node, sourceFile)); + return ''; + })(); - const start = node.pos; - const end = node.end; - const methodText = sourceFile.text.slice(start, end); - + const parameters = node.parameters.map(param => { + const paramName = (param.name as ts.Identifier).escapedText.toString(); + const paramType = param.type + ? sourceFile.text.slice(param.type.pos, param.type.end).trim() + : 'any'; + return { - name, - parameters: node.parameters.map(param => { - const paramName = (param.name as ts.Identifier).escapedText.toString(); - const paramType = param.type - ? sourceFile.text.slice(param.type.pos, param.type.end).trim() - : 'any'; - - return { - name: paramName, - type: paramType, - description: jsDoc.params[paramName] || '' - }; - }), - description: jsDoc.description, - endpoint: API_MAP[name] || '', - httpMethod: methodText.includes('this.fetchPost') ? 'POST' : 'GET', - returnType: node.type?.getText(sourceFile) || 'Promise', - responseSchema: (() => { - const fetchMatch = methodText.match(/this\.fetch\([^,]+,\s*([\w.()]+)/); - if (!fetchMatch) return ''; - - const schema = fetchMatch[1]; - if (schema.includes('z.array')) { - const arrayMatch = schema.match(/z\.array\((\w+Schema)\)/); - return arrayMatch?.[1] || ''; - } - if (schema.includes('z.number')) return 'z.number()'; - - return schema; - })(), + name: paramName, + type: paramType, + description: docInfo.params[paramName] || '' }; - } \ No newline at end of file + }); + + const methodText = sourceFile.text.slice(node.pos, node.end); + const httpMethod = methodText.includes('this.fetchPost') ? 'POST' : 'GET'; + + return { + name, + parameters, + description: docInfo.description, + endpoint, + httpMethod, + returnType: node.type?.getText(sourceFile) || 'Promise', + recursive: endpoint.startsWith('/r/') + }; +} \ No newline at end of file diff --git a/docs/generateTypesDocs.ts b/docs/generateTypesDocs.ts index 8c30b78..8a438c0 100644 --- a/docs/generateTypesDocs.ts +++ b/docs/generateTypesDocs.ts @@ -47,10 +47,13 @@ function parseZodType(zodType: string): string { } if (type.startsWith('z.record')) { - const matches = type.match(/z\.record\((.*?),\s*(.*?)\)/); + const matches = type.match(/z\.record\((.*?),\s*([\s\S]*?)\)(?![\s\S]*\)$)/); if (!matches) return 'Record'; const [_, keyType, valueType] = matches; - return `Record<${parseZodType(keyType)}, ${parseZodType(valueType)}>`; + const parsedValueType = parseZodType(valueType.trim()); + const parsedKeyType = parseZodType(keyType.trim()); + + return `Record<${parsedKeyType}, ${parsedValueType}>`; } if (type.startsWith('z.tuple')) { @@ -71,18 +74,26 @@ function parseZodType(zodType: string): string { } function findTypeDescription(typeName: string, typeFileContent: string): string { - // Look for JSDoc comment followed by the type definition const regex = new RegExp( - `/\\*\\*\\s*\\n\\s*\\*\\s*([^\\n]+)\\s*\\n[^/]*\\*/\\s*export\\s+type\\s+${typeName}\\s*=`, - 'ms' + `\\/\\*\\*([^*]*\\*+(?:[^/*][^*]*\\*+)*)\\/\\s*export\\s+type\\s+${typeName}\\b`, + 'g' ); const match = regex.exec(typeFileContent); - return match ? match[1].trim() : ''; + if (!match) return ''; + + return match[1] + .split('\n') + .map(line => line.trim() + .replace(/^\*\s*/, '') + .replace(/\s*\*\/$/, '') + ) + .filter(Boolean) + .join(' ') + .trim(); } export function extractZodSchema(schemaContent: string, filename: string): CustomType[] { - // Try to read types file let typeFileContent = ''; try { const typeFilePath = path.join(process.cwd(), 'src', 'types', 'index.ts'); diff --git a/docs/scripts.js b/docs/scripts.js new file mode 100644 index 0000000..f1069e8 --- /dev/null +++ b/docs/scripts.js @@ -0,0 +1,99 @@ +function initializeTabs() { + const buttons = document.querySelectorAll('button[data-tab]'); + const sections = { + methods: document.getElementById('methods-content'), + types: document.getElementById('types-content') + }; + const scrollPositions = { + methods: 0, + types: 0 + }; + + buttons.forEach(button => { + button.addEventListener('click', () => { + const tab = button.getAttribute('data-tab'); + + const activeTab = [...buttons] + .find(b => b.classList.contains('active')) + ?.getAttribute('data-tab'); + + if (activeTab) { + scrollPositions[activeTab] = sections[activeTab].scrollTop; + } + + buttons.forEach(b => { + if (b === button) { + b.classList.add('active'); + } else { + b.classList.remove('active'); + } + }); + + Object.values(sections).forEach(section => { + section.classList.remove('active'); + }); + + if (sections[tab]) { + sections[tab].classList.add('active'); + sections[tab].scrollTop = scrollPositions[tab]; + } else { + console.error('Section not found:', tab); + } + }); + }); + + Object.entries(sections).forEach(([tab, section]) => { + if (section) { + section.addEventListener('scroll', () => { + scrollPositions[tab] = section.scrollTop; + }); + } else { + console.error('Section not found for scroll listener:', tab); + } + }); +} + +function initializeCollapsibles() { + const triggers = document.querySelectorAll('[data-collapse-trigger]'); + + triggers.forEach(trigger => { + trigger.addEventListener('click', () => { + const content = trigger.nextElementSibling; + const arrow = trigger.querySelector('svg'); + + if (content && arrow) { + content.classList.toggle('active'); + arrow.style.transform = content.classList.contains('active') + ? 'rotate(180deg)' + : ''; + } else { + console.error('Missing content or arrow for trigger:', trigger); + } + }); + }); +} + +function initializeTypeLinks() { + document.addEventListener('click', e => { + if (e.target.matches('a[href^="#"]')) { + const typesTab = document.querySelector('[data-tab="types"]'); + if (typesTab) { + typesTab.click(); + } else { + console.error('Types tab button not found'); + } + } + }); +} + +function initializeDocumentation() { + initializeTabs(); + initializeCollapsibles(); + initializeTypeLinks(); +} + +if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', initializeDocumentation); +} else { + initializeDocumentation(); +} \ No newline at end of file diff --git a/docs/styles.css b/docs/styles.css new file mode 100644 index 0000000..31549da --- /dev/null +++ b/docs/styles.css @@ -0,0 +1,213 @@ +:root { + --color-base: rgba(240, 240, 235, 0.95); + --color-muted: rgba(200, 200, 195, 0.85); + --color-accent: rgba(220, 220, 215, 0.07); + --color-background: #0a0a0a; + --color-border: rgba(160, 160, 155, 0.15); + --color-hover: rgba(240, 240, 235, 0.1); + --color-active: rgba(240, 240, 235, 0.15); + --color-method: rgba(240, 240, 235, 0.1); + + --header-height: 4.5rem; + --header-height-sm: 7rem; + + --text-body-sm: 0.75rem; + --text-body: 0.875rem; + --text-title: 1.125rem; + --text-header: 1.5rem; + + --space-sm: 0.5rem; + --space-md: 1rem; + --space-lg: 1.5rem; + + --border-opacity: 0.12; + --hover-opacity: 1; + + --header-border-width: 1px; + --header-border-opacity: 0.08; +} + +html, body { + height: 100%; + overflow: hidden; +} + +@keyframes scanline { + 0% { + transform: translateY(-100%); + } + 100% { + transform: translateY(100%); + } +} + +body::after { + content: ""; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: linear-gradient( + transparent 50%, + rgba(240, 240, 235, 0.01) 50% + ); + background-size: 100% 3px; + pointer-events: none; + z-index: 100; +} + +.main-layout { + height: 100vh; + display: flex; + flex-direction: column; +} + +.content-wrapper { + flex: 1; + overflow: hidden; + position: relative; +} + +.tab-content { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + overflow-y: auto; + display: none; + padding: var(--space-md); +} + +@media (min-width: 640px) { + .tab-content { + padding: var(--space-lg); + } + :root { + --header-height: 5rem; + } +} + +.tab-content.active { + display: block; +} + +.type-link { + text-decoration: underline; + text-decoration-color: var(--color-muted); + text-underline-offset: 2px; + opacity: 0.85; +} + +.type-link:hover { + opacity: var(--hover-opacity); + color: var(--color-base); +} + +.section-content { + display: none; +} + +.section-content.active { + display: block; +} + +::selection { + background: rgba(240, 240, 235, 0.2); + color: var(--color-base); +} + +.nav-button { + font-size: var(--text-body); + padding: var(--space-sm) var(--space-md); + border-radius: 0.25rem; + transition: all 0.15s ease; + border: 1px solid var(--color-border); + color: var(--color-muted); + background: transparent; +} + +.nav-button:hover { + border-color: var(--color-muted); + color: var(--color-base); + background: var(--color-hover); +} + +.nav-button.active { + border-color: var(--color-base); + background-color: var(--color-active); + color: var(--color-base); +} + +.doc-section { + border: 1px solid var(--color-border); + border-radius: 0.375rem; + background-color: var(--color-background); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2); +} + +.doc-header { + border-bottom: 1px solid var(--color-border); + background-color: var(--color-accent); + padding: var(--space-md) var(--space-lg); +} + +.github-button { + border-color: var(--color-border) !important; + color: var(--color-muted) !important; + background: transparent !important; +} + +.github-button:hover { + border-color: var(--color-muted) !important; + color: var(--color-base) !important; + background: var(--color-hover) !important; +} + +.method-badge { + background-color: var(--color-method); + border: 1px solid var(--color-border); + color: var(--color-base); + font-weight: 500; + padding: 0.25rem 0.75rem; + border-radius: 0.25rem; +} + +.collapse-trigger { + transition: background-color 0.15s ease; +} + +.collapse-trigger:hover { + background-color: var(--color-hover); +} + +code { + color: var(--color-base); +} + +.parameter-block { + background-color: var(--color-accent); + border: 1px solid var(--color-border); + border-radius: 0.375rem; +} + +.sticky-header { + border-bottom: var(--header-border-width) solid var(--color-border); + background-color: var(--color-background); + backdrop-filter: blur(8px); + flex-shrink: 0; +} + +button, a { + transition: all 0.15s ease; +} + +.tab-content { + scrollbar-width: none; + -ms-overflow-style: none; +} + +.tab-content::-webkit-scrollbar { + display: none; +} \ No newline at end of file diff --git a/docs/utils/doc-parser.ts b/docs/utils/doc-parser.ts new file mode 100644 index 0000000..955286d --- /dev/null +++ b/docs/utils/doc-parser.ts @@ -0,0 +1,59 @@ +import * as ts from 'typescript'; + +export interface ParsedDoc { + description: string; + params: Record; + returnType?: string; +} + +export function extractDocComment(node: ts.Node, sourceFile: ts.SourceFile): string { + const ranges = ts.getLeadingCommentRanges(sourceFile.text, node.pos); + if (!ranges || ranges.length === 0) return ''; + + const commentRange = ranges[ranges.length - 1]; + return sourceFile.text.substring(commentRange.pos, commentRange.end); +} + +export function parseDocComment(comment: string): ParsedDoc { + if (!comment) { + return { description: '', params: {} }; + } + + const result: ParsedDoc = { + description: '', + params: {}, + }; + + const lines = comment + .replace(/\/\*\*|\*\/|\*/g, '') + .split('\n') + .map(line => line.trim()) + .filter(Boolean); + + let currentSection = 'description'; + + for (const line of lines) { + if (line.startsWith('@param')) { + const paramMatch = line.match(/@param\s+(\w+)\s*-?\s*(.*)/); + if (paramMatch) { + const [, name, description] = paramMatch; + result.params[name] = description || ''; + } + continue; + } + + if (line.startsWith('@returns')) { + const returnMatch = line.match(/@returns\s+(.*)/); + if (returnMatch) { + result.returnType = returnMatch[1]; + } + continue; + } + + if (!line.startsWith('@') && currentSection === 'description') { + result.description += (result.description ? ' ' : '') + line; + } + } + + return result; +} \ No newline at end of file diff --git a/src/api.ts b/src/api.ts index d208c6e..b5a53ca 100644 --- a/src/api.ts +++ b/src/api.ts @@ -1,41 +1,55 @@ import { OutputType } from './types'; const api = { - address: (address: string) => `/address/${address}`, - block: (heightOrHash: number | string) => `/block/${heightOrHash}`, - blockcount: '/blockcount', - blockhash: { - latest: '/blockhash', - byHeight: (height: number) => `/blockhash/${height}`, + getAddressInfo: (address: string) => `/address/${address}`, + getBlockInfo: (heightOrHash: number | string) => `/block/${heightOrHash}`, + getBlockCount: '/blockcount', + getBlockHashByHeight: (height: number) => `/blockhash/${height}`, + getBlockHash: '/blockhash', + getBlockHeight: '/blockheight', + getBlocksLatest: '/blocks', + getBlockTime: '/blocktime', + getInscriptionInfo: (id: string) => `/inscription/${id}`, + getChild: (id: string, child: number) => `/inscription/${id}/${child}`, + getInscriptions: '/inscriptions', + getInscriptionsByIds: '/inscriptions', + getInscriptionsByPage: (page: number) => `/inscriptions/${page}`, + getInscriptionsByBlock: (height: number) => `/inscriptions/block/${height}`, + getOutput: (outpoint: string) => `/output/${outpoint}`, + getOutputs: '/outputs', + getOutputsByAddress: (address: string, type?: OutputType) => { + const base = `/outputs/${address}`; + return type ? `${base}?type=${type}` : base; }, - blockheight: '/blockheight', - blocks: '/blocks', - blocktime: '/blocktime', - inscription: (id: string) => `/inscription/${id}`, - inscriptionChild: (id: string, child: number) => - `/inscription/${id}/${child}`, - inscriptions: { - base: '/inscriptions', - latest: '/inscriptions', - byPage: (page: number) => `/inscriptions/${page}`, - byBlock: (height: number) => `/inscriptions/block/${height}`, - }, - output: (outpoint: string) => `/output/${outpoint}`, - outputs: { - base: '/outputs', - byAddress: (address: string, type?: OutputType) => { - const base = `/outputs/${address}`; - return type ? `${base}?type=${type}` : base; - }, - }, - rune: (name: string) => `/rune/${name}`, - runes: { - latest: '/runes', - byPage: (page: number) => `/runes/${page}`, - }, - sat: (number: number) => `/sat/${number}`, - tx: (txId: string) => `/tx/${txId}`, - status: '/status', + getRune: (name: string) => `/rune/${name}`, + getRunesLatest: '/runes', + getRunesByPage: (page: number) => `/runes/${page}`, + getSat: (number: number) => `/sat/${number}`, + getTransaction: (txId: string) => `/tx/${txId}`, + getServerStatus: '/status', + + // recursive endpoints + getBlockHashByHeightRecursive: (height: number) => `/r/blockhash/${height}`, + getBlockHashRecursive: '/r/blockhash', + getBlockHeightRecursive: '/r/blockheight', + getBlockInfoRecursive: (heightOrHash: number | string) => + `/r/blockinfo/${heightOrHash}`, + getBlockTimeRecursive: '/r/blocktime', + getChildren: (id: string) => `/r/children/${id}`, + getChildrenByPage: (id: string, page: number) => `/r/children/${id}/${page}`, + getChildrenInfo: (id: string) => `/r/children/${id}/inscriptions`, + getChildrenInfoByPage: (id: string, page: number) => + `/r/children/${id}/inscriptions/${page}`, + getInscriptionRecursive: (id: string) => `/r/inscription/${id}`, + getParents: (id: string) => `/r/parents/${id}`, + getParentsByPage: (id: string, page: number) => `/r/parents/${id}/${page}`, + getInscriptionsOnSat: (number: number) => `/r/sat/${number}`, + getInscriptionsOnSatByPage: (number: number, page: number) => + `/r/sat/${number}/${page}`, + getInscriptionOnSat: (number: number, index: number) => + `/r/sat/${number}/at/${index}`, + getTransactionHex: (txid: string) => `/r/tx/${txid}`, + getOutputAssets: (outpoint: string) => `/r/utxo/${outpoint}`, } as const; export default api; diff --git a/src/client.ts b/src/client.ts index d42aba0..d898761 100644 --- a/src/client.ts +++ b/src/client.ts @@ -13,6 +13,13 @@ import { SatInfoSchema, ServerStatusSchema, TransactionInfoSchema, + BlockDetailsSchema, + InscriptionsIDsResponseSchema, + ChildrenInfoResponseSchema, + InscriptionIDSchema, + OutputAssetsSchema, + TransactionHexSchema, + InscriptionRecursiveSchema, } from './schemas'; import type { BlockInfo, @@ -28,6 +35,13 @@ import type { TransactionInfo, ServerStatus, OutputType, + BlockDetails, + InscriptionsIDsResponse, + ChildrenInfoResponse, + InscriptionID, + OutputAssets, + TransactionHex, + InscriptionRecursive, } from './types'; type ApiResponse = @@ -110,119 +124,152 @@ export class OrdClient { * inscriptions, and rune balances. * * @param {string} address - Bitcoin address to query. - * @returns {Promise} Address details including outputs and balances. */ async getAddressInfo(address: string): Promise { - return this.fetch(api.address(address), AddressInfoSchema); + return this.fetch(api.getAddressInfo(address), AddressInfoSchema); } /** * Fetches details about a specific block by its height or hash. * * @param {number | BlockHash} heightOrHash - Block height (number) or block hash (string). - * @returns {Promise} Detailed information about the block. */ - async getBlock(heightOrHash: number | BlockHash): Promise { - return this.fetch(api.block(heightOrHash), BlockInfoSchema); + async getBlockInfo(heightOrHash: number | BlockHash): Promise { + return this.fetch(api.getBlockInfo(heightOrHash), BlockInfoSchema); } /** - * Retrieves the total number of blocks in the blockchain. + * Gets detailed block information using the recursive endpoint. * - * @returns {Promise} Current block count + * @param {number | string} heightOrHash - Block height or hash + */ + async getBlockInfoRecursive( + heightOrHash: number | string, + ): Promise { + return this.fetch( + api.getBlockInfoRecursive(heightOrHash), + BlockDetailsSchema, + ); + } + + /** + * Retrieves the total number of blocks in the blockchain. */ async getBlockCount(): Promise { - return this.fetch(api.blockcount, z.number().int().nonnegative()); + return this.fetch(api.getBlockCount, z.number().int().nonnegative()); + } + + /** + * Gets the hash of the latest block. + */ + async getBlockHash(): Promise { + return this.fetch(api.getBlockHash, BlockHashSchema); + } + + /** + * Gets the latest block hash using the recursive endpoint. + * + * @returns {Promise} Latest block hash + */ + async getBlockHashRecursive(): Promise { + return this.fetch(api.getBlockHashRecursive, BlockHashSchema); } /** * Gets the hash of a block at the specified height. * * @param {number} height - Block height to get hash for - * @returns {Promise} Block hash */ async getBlockHashByHeight(height: number): Promise { - return this.fetch(api.blockhash.byHeight(height), BlockHashSchema); + return this.fetch(api.getBlockHashByHeight(height), BlockHashSchema); } /** - * Gets the hash of the latest block. + * Gets the block hash using the recursive endpoint. * - * @returns {Promise} Latest block hash + * @param {number} height - Block height */ - async getLatestBlockHash(): Promise { - return this.fetch(api.blockhash.latest, BlockHashSchema); + async getBlockHashByHeightRecursive(height: number): Promise { + return this.fetch( + api.getBlockHashByHeightRecursive(height), + BlockHashSchema, + ); } /** * Gets the height of the latest block. - * - * @returns {Promise} Latest block height */ - async getLatestBlockHeight(): Promise { - return this.fetch(api.blockheight, z.number().int().nonnegative()); + async getBlockHeight(): Promise { + return this.fetch(api.getBlockHeight, z.number().int().nonnegative()); + } + + /** + * Gets the latest block height using the recursive endpoint. + */ + async getBlockHeightRecursive(): Promise { + return this.fetch( + api.getBlockHeightRecursive, + z.number().int().nonnegative(), + ); } /** * Returns the height of the latest block, the blockhashes of the last 100 blocks, and featured inscriptions from them. - * - * @returns {Promise} Latest blocks information */ - async getLatestBlocks(): Promise { - return this.fetch(api.blocks, BlocksResponseSchema); + async getBlocksLatest(): Promise { + return this.fetch(api.getBlocksLatest, BlocksResponseSchema); } /** * Gets the timestamp of the latest block. - * - * @returns {Promise} Latest block's Unix timestamp */ - async getLatestBlockTime(): Promise { - return this.fetch(api.blocktime, z.number().int()); + async getBlockTime(): Promise { + return this.fetch(api.getBlockTime, z.number().int()); + } + + /** + * Gets block time using the recursive endpoint. + */ + async getBlockTimeRecursive(): Promise { + return this.fetch(api.getBlockTimeRecursive, z.number().int()); } /** * Retrieves information about a specific inscription by its ID. * * @param {string} id - Inscription ID - * @returns {Promise} Detailed information about the inscription */ - async getInscription(id: string): Promise { - return this.fetch(api.inscription(id), InscriptionInfoSchema); + async getInscriptionInfo(id: string): Promise { + return this.fetch(api.getInscriptionInfo(id), InscriptionInfoSchema); } /** - * Gets a specific child inscription of a parent inscription. + * Gets recursive inscription information. * - * @param {string} id - Parent inscription ID - * @param {number} child - Index of the child inscription - * @returns {Promise} Child inscription details + * @param {string} id - Inscription ID */ - async getInscriptionChild( - id: string, - child: number, - ): Promise { - return this.fetch(api.inscriptionChild(id, child), InscriptionInfoSchema); + async getInscriptionRecursive(id: string): Promise { + return this.fetch( + api.getInscriptionRecursive(id), + InscriptionRecursiveSchema, + ); } /** * Gets a list of the 100 most recent inscriptions. - * - * @returns {Promise} Latest inscriptions information */ - async getLatestInscriptions(): Promise { - return this.fetch(api.inscriptions.latest, InscriptionsResponseSchema); + async getInscriptions(): Promise { + return this.fetch(api.getInscriptions, InscriptionsResponseSchema); } /** * Retrieves information about multiple inscriptions by their IDs. * * @param {string[]} ids - Array of inscription IDs to fetch - * @returns {Promise} Array of inscription details */ async getInscriptionsByIds(ids: string[]): Promise { return this.fetchPost( - api.inscriptions.base, + api.getInscriptionsByIds, ids, z.array(InscriptionInfoSchema), ); @@ -232,11 +279,10 @@ export class OrdClient { * Gets inscriptions for a specific page number in paginated results. * * @param {number} page - Page number to fetch - * @returns {Promise} Page of inscriptions */ async getInscriptionsByPage(page: number): Promise { return this.fetch( - api.inscriptions.byPage(page), + api.getInscriptionsByPage(page), InscriptionsResponseSchema, ); } @@ -245,11 +291,139 @@ export class OrdClient { * Gets all inscriptions in a specific block. * * @param {number} height - Block height to fetch inscriptions from - * @returns {Promise} Block's inscriptions */ async getInscriptionsByBlock(height: number): Promise { return this.fetch( - api.inscriptions.byBlock(height), + api.getInscriptionsByBlock(height), + InscriptionsResponseSchema, + ); + } + + /** + * Gets ID of a specific inscription at an index by sat number. The inscription id at index of all inscriptions on a sat. Index may be a negative number to index from the back. 0 being the first and -1 being the most recent for example. Requires index with --index-sats flag. + * + * @param {number} number - Satoshi number + * @param {number} index - Inscription index + */ + async getInscriptionOnSat( + number: number, + index: number, + ): Promise { + return this.fetch( + api.getInscriptionOnSat(number, index), + InscriptionIDSchema, + ); + } + + /** + * Gets the first 100 inscription ids on a sat. Requires index with --index-sats flag. + * + * @param {number} number - Satoshi number + */ + async getInscriptionsOnSat(number: number): Promise { + return this.fetch( + api.getInscriptionsOnSat(number), + InscriptionsIDsResponseSchema, + ); + } + + /** + * Gets paginated inscription ids for a specific satoshi. + * + * @param {number} number - Satoshi number + * @param {number} page - Page number + */ + async getInscriptionsOnSatByPage( + number: number, + page: number, + ): Promise { + return this.fetch( + api.getInscriptionsOnSatByPage(number, page), + InscriptionsIDsResponseSchema, + ); + } + + /** + * Gets a specific child inscription of a parent inscription. + * + * @param {string} id - Parent inscription ID + * @param {number} child - Index of the child inscription + */ + async getChild(id: string, child: number): Promise { + return this.fetch(api.getChild(id, child), InscriptionInfoSchema); + } + + /** + * Gets first 100 child inscriptions IDs. + * + * @param {string} id - Parent inscription ID + */ + async getChildren(id: string): Promise { + return this.fetch(api.getChildren(id), InscriptionsIDsResponseSchema); + } + + /** + * Gets paginated child inscription IDs. + * + * @param {string} id - Parent inscription ID + * @param {number} page - Page number + */ + async getChildrenByPage( + id: string, + page: number, + ): Promise { + return this.fetch( + api.getChildrenByPage(id, page), + InscriptionsIDsResponseSchema, + ); + } + + /** + * Gets details of the first 100 child inscriptions. + * + * @param {string} id - Parent inscription ID + */ + async getChildrenInfo(id: string): Promise { + return this.fetch(api.getChildrenInfo(id), ChildrenInfoResponseSchema); + } + + /** + * Gets paginated detailed child inscription information. + * + * @param {string} id - Parent inscription ID + * @param {number} page - Page number + */ + async getChildrenInfoByPage( + id: string, + page: number, + ): Promise { + return this.fetch( + api.getChildrenInfoByPage(id, page), + ChildrenInfoResponseSchema, + ); + } + + /** + * Gets parent inscription IDs. + * + * @param {string} id - Child inscription ID + */ + async getParents(id: string): Promise { + return this.fetch(api.getParents(id), InscriptionsResponseSchema); + } + + /** + * Gets paginated parent inscription IDs. + * + * @param {string} id - Child inscription ID + * @param {number} page - Page number + */ + async getParentsByPage( + id: string, + page: number, + ): Promise { + return this.fetch( + api.getParentsByPage(id, page), InscriptionsResponseSchema, ); } @@ -258,24 +432,27 @@ export class OrdClient { * Retrieves information about a specific UTXO. * * @param {string} outpoint - Transaction outpoint in format {txid}:{vout} - * @returns {Promise} UTXO details */ async getOutput(outpoint: string): Promise { - return this.fetch(api.output(outpoint), OutputInfoSchema); + return this.fetch(api.getOutput(outpoint), OutputInfoSchema); + } + + /** + * Gets assets held by an UTXO. + * + * @param {string} outpoint - Transaction outpoint + */ + async getOutputAssets(outpoint: string): Promise { + return this.fetch(api.getOutputAssets(outpoint), OutputAssetsSchema); } /** * Gets information about multiple UTXOs. * * @param {string[]} outpoints - Array of outpoints to fetch - * @returns {Promise} Array of UTXO details */ async getOutputs(outpoints: string[]): Promise { - return this.fetchPost( - api.outputs.base, - outpoints, - z.array(OutputInfoSchema), - ); + return this.fetchPost(api.getOutputs, outpoints, z.array(OutputInfoSchema)); } /** @@ -283,14 +460,13 @@ export class OrdClient { * * @param {string} address - Bitcoin address to get outputs for * @param {OutputType} [type] - Optional filter for specific output types - * @returns {Promise} Array of address's UTXOs */ async getOutputsByAddress( address: string, type?: OutputType, ): Promise { return this.fetch( - api.outputs.byAddress(address, type), + api.getOutputsByAddress(address, type), z.array(OutputInfoSchema), ); } @@ -299,57 +475,58 @@ export class OrdClient { * Gets information about a specific rune by name. * * @param {string} name - Rune name - * @returns {Promise} Rune details */ async getRune(name: string): Promise { - return this.fetch(api.rune(name), RuneResponseSchema); + return this.fetch(api.getRune(name), RuneResponseSchema); } /** * Gets a list of the 100 most recent runes. - * - * @returns {Promise} Latest runes information */ - async getLatestRunes(): Promise { - return this.fetch(api.runes.latest, RunesResponseSchema); + async getRunesLatest(): Promise { + return this.fetch(api.getRunesLatest, RunesResponseSchema); } /** * Gets runes for a specific page number in paginated results. * * @param {number} page - Page number to fetch - * @returns {Promise} Page of runes */ async getRunesByPage(page: number): Promise { - return this.fetch(api.runes.byPage(page), RunesResponseSchema); + return this.fetch(api.getRunesByPage(page), RunesResponseSchema); } /** * Gets information about a specific satoshi by its number. * * @param {number} number - Satoshi number - * @returns {Promise} Satoshi details */ async getSat(number: number): Promise { - return this.fetch(api.sat(number), SatInfoSchema); + return this.fetch(api.getSat(number), SatInfoSchema); } /** * Gets information about a specific transaction. * * @param {string} txId - Transaction ID - * @returns {Promise} Transaction details */ async getTransaction(txId: string): Promise { - return this.fetch(api.tx(txId), TransactionInfoSchema); + return this.fetch(api.getTransaction(txId), TransactionInfoSchema); } /** - * Gets the current server status and information. + * Gets hex transaction data. * - * @returns {Promise} Server status details + * @param {string} txid - Transaction ID + */ + async getTransactionHex(txid: string): Promise { + return this.fetch(api.getTransactionHex(txid), TransactionHexSchema); + } + + /** + * Gets the current server status and information. */ async getServerStatus(): Promise { - return this.fetch(api.status, ServerStatusSchema); + return this.fetch(api.getServerStatus, ServerStatusSchema); } } diff --git a/src/schemas/block.ts b/src/schemas/block.ts index ddd17d9..1b67e10 100644 --- a/src/schemas/block.ts +++ b/src/schemas/block.ts @@ -26,3 +26,34 @@ export const BlocksResponseSchema = z.object({ blocks: z.array(BlockHashSchema), featured_blocks: z.record(BlockHashSchema, z.array(z.string())), }); + +export const BlockDetailsSchema = z.object({ + average_fee: z.number().int().nonnegative(), + average_fee_rate: z.number().nonnegative(), + bits: z.number().int().nonnegative(), + chainwork: z.string(), + confirmations: z.number().int().nonnegative(), + difficulty: z.number().nonnegative(), + hash: BlockHashSchema, + feerate_percentiles: z.array(z.number().nonnegative()), + height: z.number().int().nonnegative(), + max_fee: z.number().int().nonnegative(), + max_fee_rate: z.number().nonnegative(), + max_tx_size: z.number().int().nonnegative(), + median_fee: z.number().int().nonnegative(), + median_time: z.number().int().nonnegative().nullable(), + merkle_root: z.string(), + min_fee: z.number().int().nonnegative(), + min_fee_rate: z.number().nonnegative(), + next_block: BlockHashSchema.nullable(), + nonce: z.number().int().nonnegative(), + previous_block: BlockHashSchema.nullable(), + subsidy: z.number().int().nonnegative(), + target: z.string(), + timestamp: z.number().int(), + total_fee: z.number().int().nonnegative(), + total_size: z.number().int().nonnegative(), + total_weight: z.number().int().nonnegative(), + transaction_count: z.number().int().nonnegative(), + version: z.number().int(), +}); diff --git a/src/schemas/inscription.ts b/src/schemas/inscription.ts index c317073..1f50c2b 100644 --- a/src/schemas/inscription.ts +++ b/src/schemas/inscription.ts @@ -28,7 +28,7 @@ export const InscriptionInfoSchema = z.object({ fee: z.number().int().nonnegative(), height: z.number().int().nonnegative(), id: z.string(), - next: z.string().nullable().nullable(), + next: z.string().nullable(), number: z.number().int().nonnegative(), parents: z.array(z.string()), previous: z.string().nullable(), @@ -40,8 +40,53 @@ export const InscriptionInfoSchema = z.object({ metaprotocol: z.string().nullable(), }); +export const InscriptionRecursiveSchema = z.object({ + charms: z.array(CharmTypeSchema), + content_type: z.string().nullable(), + content_length: z.number().int().nonnegative().nullable(), + delegate: z.string().nullable(), + fee: z.number().int().nonnegative(), + height: z.number().int().nonnegative(), + id: z.string(), + number: z.number().int().nonnegative(), + output: z.string(), + sat: z.number().int().nonnegative().nullable(), + satpoint: z.string(), + timestamp: z.number().int(), + value: z.number().int().nonnegative().nullable(), + address: z.string().nullable(), +}); + export const InscriptionsResponseSchema = z.object({ ids: z.array(z.string()), more: z.boolean(), page_index: z.number().int().nonnegative(), }); + +export const InscriptionsIDsResponseSchema = z.object({ + ids: z.array(z.string()), + more: z.boolean(), + page: z.number().int().nonnegative(), +}); + +export const ChildInfoSchema = z.object({ + charms: z.array(CharmTypeSchema), + fee: z.number().int().nonnegative(), + height: z.number().int().nonnegative(), + id: z.string(), + number: z.number().int().nonnegative(), + output: z.string(), + sat: z.number().int().nonnegative(), + satpoint: z.string(), + timestamp: z.number().int(), +}); + +export const ChildrenInfoResponseSchema = z.object({ + children: z.array(ChildInfoSchema), + more: z.boolean(), + page: z.number().int().nonnegative(), +}); + +export const InscriptionIDSchema = z.object({ + id: z.string().nullable(), +}); diff --git a/src/schemas/output.ts b/src/schemas/output.ts index d7f2dc2..96abf72 100644 --- a/src/schemas/output.ts +++ b/src/schemas/output.ts @@ -1,4 +1,5 @@ import { z } from 'zod'; +import { RuneBalanceSchema } from './rune'; export const OutputTypeSchema = z.enum([ 'any', @@ -7,26 +8,27 @@ export const OutputTypeSchema = z.enum([ 'runic', ]); -const SatRangeSchema = z.tuple([ +export const SatRangeSchema = z.tuple([ z.number().int().nonnegative(), z.number().int().nonnegative(), ]); -const RuneInfoSchema = z.object({ - amount: z.number().int().nonnegative(), - divisibility: z.number().int().nonnegative(), - symbol: z.string(), -}); - export const OutputInfoSchema = z.object({ address: z.string().nullable(), indexed: z.boolean(), inscriptions: z.array(z.string()).nullable(), outpoint: z.string(), - runes: z.record(z.string(), RuneInfoSchema).nullable(), + runes: z.record(z.string(), RuneBalanceSchema).nullable(), sat_ranges: z.array(SatRangeSchema).nullable(), script_pubkey: z.string(), spent: z.boolean(), transaction: z.string(), value: z.number().int().nonnegative(), }); + +export const OutputAssetsSchema = z.object({ + inscriptions: z.array(z.string()).nullable(), + runes: z.record(z.string(), RuneBalanceSchema).nullable(), + sat_ranges: z.array(SatRangeSchema).nullable(), + value: z.number().int().nonnegative(), +}); diff --git a/src/schemas/rune.ts b/src/schemas/rune.ts index 97f5d02..92c25d4 100644 --- a/src/schemas/rune.ts +++ b/src/schemas/rune.ts @@ -9,6 +9,12 @@ export const RuneTermsSchema = z }) .nullable(); +export const RuneBalanceSchema = z.object({ + amount: z.number().int().nonnegative(), + divisibility: z.number().int().nonnegative(), + symbol: z.string(), +}); + export const RuneInfoSchema = z.object({ block: z.number().int().nonnegative(), burned: z.number().int().nonnegative(), diff --git a/src/schemas/transaction.ts b/src/schemas/transaction.ts index dccf0e6..a5c31c0 100644 --- a/src/schemas/transaction.ts +++ b/src/schemas/transaction.ts @@ -26,3 +26,10 @@ export const TransactionInfoSchema = z.object({ transaction: TransactionSchema, txid: z.string(), }); + +export const TransactionHexSchema = z + .string() + .regex( + /^[0-9a-f]+$/, + 'Transaction hex must contain only lowercase hexadecimal characters', + ); diff --git a/src/test/integration/api.test.ts b/src/test/integration/api.test.ts index e2cd42b..c2970a6 100644 --- a/src/test/integration/api.test.ts +++ b/src/test/integration/api.test.ts @@ -25,11 +25,11 @@ describe('API Integration Tests', () => { invalidClient = new OrdClient('https://invalid.api'); }); - describe('getBlock', () => { + describe('getBlockInfo', () => { test( 'fetches genesis block successfully', async () => { - const block = await client.getBlock(0); + const block = await client.getBlockInfo(0); expect(block.height).toBe(0); expect(block.hash).toBe(GENESIS_BLOCK.hash); }, @@ -39,7 +39,7 @@ describe('API Integration Tests', () => { test( 'rejects negative block height', async () => { - expect(client.getBlock(-1)).rejects.toThrow(); + expect(client.getBlockInfo(-1)).rejects.toThrow(); }, TIMEOUT, ); @@ -47,7 +47,7 @@ describe('API Integration Tests', () => { test( 'handles server error', async () => { - expect(invalidClient.getBlock(0)).rejects.toThrow(); + expect(invalidClient.getBlockInfo(0)).rejects.toThrow(); }, TIMEOUT, ); @@ -132,7 +132,7 @@ describe('API Integration Tests', () => { test( 'returns valid hash successfully', async () => { - const hash = await client.getLatestBlockHash(); + const hash = await client.getBlockHash(); expect(hash).toMatch(/^[0-9a-f]{64}$/); }, TIMEOUT, @@ -141,7 +141,7 @@ describe('API Integration Tests', () => { test( 'handles server error', async () => { - expect(invalidClient.getLatestBlockHash()).rejects.toThrow(); + expect(invalidClient.getBlockHash()).rejects.toThrow(); }, TIMEOUT, ); @@ -151,7 +151,7 @@ describe('API Integration Tests', () => { test( 'returns height successfully', async () => { - const height = await client.getLatestBlockHeight(); + const height = await client.getBlockHeight(); expect(height).toBeGreaterThan(0); }, TIMEOUT, @@ -160,7 +160,7 @@ describe('API Integration Tests', () => { test( 'handles server error', async () => { - expect(invalidClient.getLatestBlockHeight()).rejects.toThrow(); + expect(invalidClient.getBlockHeight()).rejects.toThrow(); }, TIMEOUT, ); @@ -170,7 +170,7 @@ describe('API Integration Tests', () => { test( 'returns blocks list successfully', async () => { - const blocksResponse = await client.getLatestBlocks(); + const blocksResponse = await client.getBlocksLatest(); expect(typeof blocksResponse.last).toBe('number'); expect(Array.isArray(blocksResponse.blocks)).toBe(true); @@ -186,7 +186,7 @@ describe('API Integration Tests', () => { test( 'handles server error', async () => { - expect(invalidClient.getLatestBlocks()).rejects.toThrow(); + expect(invalidClient.getBlocksLatest()).rejects.toThrow(); }, TIMEOUT, ); @@ -196,7 +196,7 @@ describe('API Integration Tests', () => { test( 'returns timestamp successfully', async () => { - const time = await client.getLatestBlockTime(); + const time = await client.getBlockTime(); expect(time).toBeGreaterThan(0); }, TIMEOUT, @@ -205,7 +205,7 @@ describe('API Integration Tests', () => { test( 'handles server error', async () => { - expect(invalidClient.getLatestBlockTime()).rejects.toThrow(); + expect(invalidClient.getBlockTime()).rejects.toThrow(); }, TIMEOUT, ); @@ -215,7 +215,9 @@ describe('API Integration Tests', () => { test( 'fetches inscription successfully', async () => { - const inscription = await client.getInscription(SAMPLE_INSCRIPTION_ID); + const inscription = await client.getInscriptionInfo( + SAMPLE_INSCRIPTION_ID, + ); expect(inscription.id).toBe(SAMPLE_INSCRIPTION_ID); expect(inscription.address).toBeDefined(); expect(Array.isArray(inscription.charms)).toBe(true); @@ -228,7 +230,7 @@ describe('API Integration Tests', () => { 'handles server error', async () => { expect( - invalidClient.getInscription(SAMPLE_INSCRIPTION_ID), + invalidClient.getInscriptionInfo(SAMPLE_INSCRIPTION_ID), ).rejects.toThrow(); }, TIMEOUT, @@ -239,10 +241,7 @@ describe('API Integration Tests', () => { test( 'fetches child inscription successfully', async () => { - const child = await client.getInscriptionChild( - SAMPLE_INSCRIPTION_ID, - 0, - ); + const child = await client.getChild(SAMPLE_INSCRIPTION_ID, 0); expect(child.id).toBeDefined(); expect(Array.isArray(child.children)).toBe(true); expect(child.parents).toContain(SAMPLE_INSCRIPTION_ID); @@ -254,7 +253,7 @@ describe('API Integration Tests', () => { 'handles server error', async () => { expect( - invalidClient.getInscriptionChild(SAMPLE_INSCRIPTION_ID, 0), + invalidClient.getChild(SAMPLE_INSCRIPTION_ID, 0), ).rejects.toThrow(); }, TIMEOUT, @@ -265,7 +264,7 @@ describe('API Integration Tests', () => { test( 'fetches latest inscriptions successfully', async () => { - const response = await client.getLatestInscriptions(); + const response = await client.getInscriptions(); expect(Array.isArray(response.ids)).toBe(true); expect(response.ids.length).toBeGreaterThan(0); expect(typeof response.more).toBe('boolean'); @@ -277,7 +276,7 @@ describe('API Integration Tests', () => { test( 'handles server error', async () => { - expect(invalidClient.getLatestInscriptions()).rejects.toThrow(); + expect(invalidClient.getInscriptions()).rejects.toThrow(); }, TIMEOUT, ); @@ -503,7 +502,7 @@ describe('API Integration Tests', () => { test( 'fetches latest runes successfully', async () => { - const response = await client.getLatestRunes(); + const response = await client.getRunesLatest(); expect(Array.isArray(response.entries)).toBe(true); expect(typeof response.more).toBe('boolean'); if (response.entries.length > 0) { @@ -518,7 +517,7 @@ describe('API Integration Tests', () => { test( 'handles server error', async () => { - expect(invalidClient.getLatestRunes()).rejects.toThrow(); + expect(invalidClient.getRunesLatest()).rejects.toThrow(); }, TIMEOUT, ); diff --git a/src/test/integration/recursiveApi.test.ts b/src/test/integration/recursiveApi.test.ts new file mode 100644 index 0000000..4af54fc --- /dev/null +++ b/src/test/integration/recursiveApi.test.ts @@ -0,0 +1,442 @@ +import { expect, test, describe, beforeAll } from 'bun:test'; +import OrdClient from '../../index'; +import { BASE_URL, TIMEOUT } from '../config/test-config'; +import { + GENESIS_BLOCK, + SAMPLE_INSCRIPTION_ID, + SAMPLE_CHILD_ID, + SAMPLE_SAT_NUMBER, + SAMPLE_TX_ID, + SAMPLE_OUTPOINT_A, +} from '../data/test-data'; + +describe('Recursive API Integration Tests', () => { + let client: OrdClient; + let invalidClient: OrdClient; + + beforeAll(() => { + client = new OrdClient(BASE_URL); + invalidClient = new OrdClient('https://invalid.api'); + }); + + describe('getBlockHashRecursive', () => { + test( + 'returns latest block hash successfully', + async () => { + const hash = await client.getBlockHashRecursive(); + expect(hash).toMatch(/^[0-9a-f]{64}$/); + }, + TIMEOUT, + ); + + test( + 'handles server error', + async () => { + expect(invalidClient.getBlockHashRecursive()).rejects.toThrow(); + }, + TIMEOUT, + ); + }); + + describe('getBlockHashByHeightRecursive', () => { + test( + 'returns genesis block hash successfully', + async () => { + const hash = await client.getBlockHashByHeightRecursive(0); + expect(hash).toBe(GENESIS_BLOCK.hash); + }, + TIMEOUT, + ); + + test( + 'rejects negative height', + async () => { + expect(client.getBlockHashByHeightRecursive(-1)).rejects.toThrow(); + }, + TIMEOUT, + ); + + test( + 'handles server error', + async () => { + expect( + invalidClient.getBlockHashByHeightRecursive(0), + ).rejects.toThrow(); + }, + TIMEOUT, + ); + }); + + describe('getBlockHeightRecursive', () => { + test( + 'returns height successfully', + async () => { + const height = await client.getBlockHeightRecursive(); + expect(height).toBeGreaterThan(0); + }, + TIMEOUT, + ); + + test( + 'handles server error', + async () => { + expect(invalidClient.getBlockHeightRecursive()).rejects.toThrow(); + }, + TIMEOUT, + ); + }); + + describe('getBlockTimeRecursive', () => { + test( + 'returns timestamp successfully', + async () => { + const time = await client.getBlockTimeRecursive(); + expect(time).toBeGreaterThan(0); + }, + TIMEOUT, + ); + + test( + 'handles server error', + async () => { + expect(invalidClient.getBlockTimeRecursive()).rejects.toThrow(); + }, + TIMEOUT, + ); + }); + + describe('getBlockInfoRecursive', () => { + test( + 'fetches block info by height successfully', + async () => { + const block = await client.getBlockInfoRecursive(0); + expect(block.height).toBe(0); + expect(block.hash).toBe(GENESIS_BLOCK.hash); + expect(block.chainwork).toBeDefined(); + expect(block.bits).toBeDefined(); + expect(block.merkle_root).toBeDefined(); + }, + TIMEOUT, + ); + + test( + 'fetches block info by hash successfully', + async () => { + const block = await client.getBlockInfoRecursive(GENESIS_BLOCK.hash); + expect(block.height).toBe(0); + expect(block.hash).toBe(GENESIS_BLOCK.hash); + expect(block.chainwork).toBeDefined(); + expect(block.bits).toBeDefined(); + expect(block.merkle_root).toBeDefined(); + }, + TIMEOUT, + ); + + test( + 'handles server error', + async () => { + expect(invalidClient.getBlockInfoRecursive(0)).rejects.toThrow(); + }, + TIMEOUT, + ); + }); + + describe('getInscriptionRecursive', () => { + test( + 'fetches inscription info successfully', + async () => { + const inscription = await client.getInscriptionRecursive( + SAMPLE_INSCRIPTION_ID, + ); + expect(inscription.id).toBe(SAMPLE_INSCRIPTION_ID); + expect(inscription.content_length).toBeGreaterThan(0); + expect(inscription.height).toBeGreaterThan(0); + expect(Array.isArray(inscription.charms)).toBe(true); + expect(typeof inscription.satpoint).toBe('string'); + }, + TIMEOUT, + ); + + test( + 'handles server error', + async () => { + expect( + invalidClient.getInscriptionRecursive(SAMPLE_INSCRIPTION_ID), + ).rejects.toThrow(); + }, + TIMEOUT, + ); + }); + + describe('getChildren', () => { + test( + 'fetches children ids successfully', + async () => { + const children = await client.getChildren(SAMPLE_INSCRIPTION_ID); + expect(Array.isArray(children.ids)).toBe(true); + }, + TIMEOUT, + ); + + test( + 'handles server error', + async () => { + expect( + invalidClient.getChildren(SAMPLE_INSCRIPTION_ID), + ).rejects.toThrow(); + }, + TIMEOUT, + ); + }); + + describe('getChildrenByPage', () => { + test( + 'fetches paginated children ids successfully', + async () => { + const children = await client.getChildrenByPage( + SAMPLE_INSCRIPTION_ID, + 0, + ); + expect(Array.isArray(children.ids)).toBe(true); + expect(children.page).toBe(0); + }, + TIMEOUT, + ); + + test( + 'handles server error', + async () => { + expect( + invalidClient.getChildrenByPage(SAMPLE_INSCRIPTION_ID, 0), + ).rejects.toThrow(); + }, + TIMEOUT, + ); + }); + + describe('getChildrenInfo', () => { + test( + 'fetches children info successfully', + async () => { + const children = await client.getChildrenInfo(SAMPLE_INSCRIPTION_ID); + expect(typeof children.more).toBe('boolean'); + expect(typeof children.page).toBe('number'); + expect(children.page).toBeGreaterThanOrEqual(0); + expect(Array.isArray(children.children)).toBe(true); + if (children.children.length > 0) { + const child = children.children[0]; + expect(Array.isArray(child.charms)).toBe(true); + expect(typeof child.fee).toBe('number'); + expect(typeof child.height).toBe('number'); + expect(typeof child.id).toBe('string'); + expect(typeof child.number).toBe('number'); + expect(typeof child.output).toBe('string'); + expect(typeof child.sat).toBe('number'); + expect(typeof child.satpoint).toBe('string'); + expect(typeof child.timestamp).toBe('number'); + } + }, + TIMEOUT, + ); + + test( + 'handles server error', + async () => { + expect( + invalidClient.getChildrenInfo(SAMPLE_INSCRIPTION_ID), + ).rejects.toThrow(); + }, + TIMEOUT, + ); + }); + + describe('getChildrenInfoByPage', () => { + test( + 'fetches paginated children info successfully', + async () => { + const children = await client.getChildrenInfoByPage( + SAMPLE_INSCRIPTION_ID, + 0, + ); + expect(typeof children.more).toBe('boolean'); + expect(typeof children.page).toBe('number'); + expect(children.page).toBeGreaterThanOrEqual(0); + expect(Array.isArray(children.children)).toBe(true); + if (children.children.length > 0) { + const child = children.children[0]; + expect(Array.isArray(child.charms)).toBe(true); + expect(typeof child.fee).toBe('number'); + expect(typeof child.height).toBe('number'); + expect(typeof child.id).toBe('string'); + expect(typeof child.number).toBe('number'); + expect(typeof child.output).toBe('string'); + expect(typeof child.sat).toBe('number'); + expect(typeof child.satpoint).toBe('string'); + expect(typeof child.timestamp).toBe('number'); + } + }, + TIMEOUT, + ); + + test( + 'handles server error', + async () => { + expect( + invalidClient.getChildrenInfoByPage(SAMPLE_INSCRIPTION_ID, 0), + ).rejects.toThrow(); + }, + TIMEOUT, + ); + }); + + describe('getParents', () => { + test( + 'fetches parent ids successfully', + async () => { + const parents = await client.getParents(SAMPLE_CHILD_ID); + expect(Array.isArray(parents.ids)).toBe(true); + }, + TIMEOUT, + ); + + test( + 'handles server error', + async () => { + expect(invalidClient.getParents(SAMPLE_CHILD_ID)).rejects.toThrow(); + }, + TIMEOUT, + ); + }); + + describe('getParentsByPage', () => { + test( + 'fetches paginated parent ids successfully', + async () => { + const parents = await client.getParentsByPage(SAMPLE_CHILD_ID, 0); + expect(Array.isArray(parents.ids)).toBe(true); + }, + TIMEOUT, + ); + + test( + 'handles server error', + async () => { + expect( + invalidClient.getParentsByPage(SAMPLE_CHILD_ID, 0), + ).rejects.toThrow(); + }, + TIMEOUT, + ); + }); + + describe('getInscriptionOnSat', () => { + test( + 'fetches inscription at index successfully', + async () => { + const inscription = await client.getInscriptionOnSat( + SAMPLE_SAT_NUMBER, + 0, + ); + expect(inscription.id).toBe(null); + }, + TIMEOUT, + ); + + test( + 'handles server error', + async () => { + expect( + invalidClient.getInscriptionOnSat(SAMPLE_SAT_NUMBER, 0), + ).rejects.toThrow(); + }, + TIMEOUT, + ); + }); + + describe('getInscriptionsOnSat', () => { + test( + 'fetches inscriptions successfully', + async () => { + const inscriptions = + await client.getInscriptionsOnSat(SAMPLE_SAT_NUMBER); + expect(Array.isArray(inscriptions.ids)).toBe(true); + }, + TIMEOUT, + ); + + test( + 'handles server error', + async () => { + expect( + invalidClient.getInscriptionsOnSat(SAMPLE_SAT_NUMBER), + ).rejects.toThrow(); + }, + TIMEOUT, + ); + }); + + describe('getInscriptionsOnSatByPage', () => { + test( + 'fetches paginated inscriptions successfully', + async () => { + const inscriptions = await client.getInscriptionsOnSatByPage( + SAMPLE_SAT_NUMBER, + 0, + ); + expect(Array.isArray(inscriptions.ids)).toBe(true); + }, + TIMEOUT, + ); + + test( + 'handles server error', + async () => { + expect( + invalidClient.getInscriptionsOnSatByPage(SAMPLE_SAT_NUMBER, 0), + ).rejects.toThrow(); + }, + TIMEOUT, + ); + }); + + describe('getOutputAssets', () => { + test( + 'fetches output info successfully', + async () => { + const output = await client.getOutputAssets(SAMPLE_OUTPOINT_A); + expect(output.value).toBeGreaterThanOrEqual(0); + }, + TIMEOUT, + ); + + test( + 'handles server error', + async () => { + expect( + invalidClient.getOutputAssets(SAMPLE_OUTPOINT_A), + ).rejects.toThrow(); + }, + TIMEOUT, + ); + }); + + describe('getTransactionHex', () => { + test( + 'fetches transaction hex successfully', + async () => { + const hex = await client.getTransactionHex(SAMPLE_TX_ID); + expect(typeof hex).toBe('string'); + expect(hex).toMatch(/^[0-9a-f]+$/); + }, + TIMEOUT, + ); + + test( + 'handles server error', + async () => { + expect(invalidClient.getTransactionHex(SAMPLE_TX_ID)).rejects.toThrow(); + }, + TIMEOUT, + ); + }); +}); diff --git a/src/test/unit/schemas.test.ts b/src/test/unit/schemas.test.ts index 91a1378..3bdd3a0 100644 --- a/src/test/unit/schemas.test.ts +++ b/src/test/unit/schemas.test.ts @@ -8,14 +8,19 @@ import { AddressInfoSchema } from '../../schemas/address'; import { InputSchema, OutputSchema, + TransactionHexSchema, TransactionSchema, } from '../../schemas/transaction'; import { + ChildInfoSchema, + ChildrenInfoResponseSchema, + InscriptionIDSchema, InscriptionInfoSchema, + InscriptionRecursiveSchema, InscriptionsResponseSchema, } from '../../schemas/inscription'; -import { OutputInfoSchema } from '../../schemas/output'; -import { RuneInfoSchema, RunesResponseSchema } from '../../schemas/rune'; +import { OutputAssetsSchema, OutputInfoSchema, SatRangeSchema } from '../../schemas/output'; +import { RuneBalanceSchema, RuneInfoSchema, RunesResponseSchema } from '../../schemas/rune'; import { SatInfoSchema } from '../../schemas/sat'; import { ServerStatusSchema } from '../../schemas/status'; import { @@ -25,7 +30,6 @@ import { SAMPLE_TRANSACTION, SAMPLE_INPUT, SAMPLE_OUTPUT, - SAMPLE_RUNE_BALANCE, SAMPLE_INSCRIPTION, SAMPLE_INSCRIPTIONS_RESPONSE, SAMPLE_UTXO_INFO, @@ -97,6 +101,68 @@ describe('Schema Validation', () => { expect(TransactionSchema.safeParse(invalidTx).success).toBe(false); }); }); + + describe('TransactionHexSchema', () => { + test('validates valid hex string', () => { + expect(TransactionHexSchema.safeParse("0123456789abcdef").success).toBe(true); + }); + + test('rejects non-hex characters', () => { + expect(TransactionHexSchema.safeParse("0123456789abcdefg").success).toBe(false); + }); + + test('rejects uppercase hex', () => { + expect(TransactionHexSchema.safeParse("0123456789ABCDEF").success).toBe(false); + }); + }); + + describe('OutputAssetsSchema', () => { + test('validates valid output assets', () => { + const validAssets = { + inscriptions: [], + runes: {}, + sat_ranges: [], + value: 1000 + }; + expect(OutputAssetsSchema.safeParse(validAssets).success).toBe(true); + }); + + test('validates null fields', () => { + const validAssets = { + inscriptions: null, + runes: null, + sat_ranges: null, + value: 1000 + }; + expect(OutputAssetsSchema.safeParse(validAssets).success).toBe(true); + }); + + test('rejects negative value', () => { + const invalidAssets = { + inscriptions: [], + runes: {}, + sat_ranges: [], + value: -1000 + }; + expect(OutputAssetsSchema.safeParse(invalidAssets).success).toBe(false); + }); + }); + + describe('SatRangeSchema', () => { + test('validates valid sat range', () => { + expect(SatRangeSchema.safeParse([0, 1000]).success).toBe(true); + }); + + test('rejects negative numbers', () => { + expect(SatRangeSchema.safeParse([-1, 1000]).success).toBe(false); + expect(SatRangeSchema.safeParse([0, -1000]).success).toBe(false); + }); + + test('rejects wrong tuple length', () => { + expect(SatRangeSchema.safeParse([0]).success).toBe(false); + expect(SatRangeSchema.safeParse([0, 1000, 2000]).success).toBe(false); + }); + }); }); describe('Block Schemas', () => { @@ -227,7 +293,9 @@ describe('Schema Validation', () => { ...SAMPLE_INSCRIPTION, charms: ['invalid_charm'], }; - const result = InscriptionInfoSchema.safeParse(inscriptionWithInvalidCharm); + const result = InscriptionInfoSchema.safeParse( + inscriptionWithInvalidCharm, + ); expect(result.success).toBe(false); }); @@ -238,7 +306,9 @@ describe('Schema Validation', () => { children: [], parents: [], }; - const result = InscriptionInfoSchema.safeParse(inscriptionWithEmptyArrays); + const result = InscriptionInfoSchema.safeParse( + inscriptionWithEmptyArrays, + ); expect(result.success).toBe(true); }); @@ -263,7 +333,9 @@ describe('Schema Validation', () => { fee: -1, value: -1, }; - const result = InscriptionInfoSchema.safeParse(inscriptionWithNegatives); + const result = InscriptionInfoSchema.safeParse( + inscriptionWithNegatives, + ); expect(result.success).toBe(false); }); }); @@ -286,6 +358,114 @@ describe('Schema Validation', () => { expect(result.success).toBe(false); }); }); + + describe('InscriptionRecursiveSchema', () => { + test('validates valid recursive inscription', () => { + const validInscription = { + charms: ["rare", "uncommon"], + content_type: "text/plain", + content_length: 100, + delegate: null, + fee: 1000, + height: 1000, + id: "abc123", + number: 1, + output: "txid:0", + sat: 1000, + satpoint: "txid:0:0", + timestamp: 1234567890, + value: 1000, + address: "bc1..." + }; + expect(InscriptionRecursiveSchema.safeParse(validInscription).success).toBe(true); + }); + + test('validates null fields', () => { + const validInscription = { + charms: [], + content_type: null, + content_length: null, + delegate: null, + fee: 1000, + height: 1000, + id: "abc123", + number: 1, + output: "txid:0", + sat: null, + satpoint: "txid:0:0", + timestamp: 1234567890, + value: null, + address: null + }; + expect(InscriptionRecursiveSchema.safeParse(validInscription).success).toBe(true); + }); + }); + + describe('ChildInfoSchema', () => { + test('validates valid child info', () => { + const validChild = { + charms: ["rare"], + fee: 1000, + height: 1000, + id: "abc123", + number: 1, + output: "txid:0", + sat: 1000, + satpoint: "txid:0:0", + timestamp: 1234567890 + }; + expect(ChildInfoSchema.safeParse(validChild).success).toBe(true); + }); + + test('rejects negative numbers', () => { + const invalidChild = { + charms: ["rare"], + fee: -1000, + height: 1000, + id: "abc123", + number: 1, + output: "txid:0", + sat: 1000, + satpoint: "txid:0:0", + timestamp: 1234567890 + }; + expect(ChildInfoSchema.safeParse(invalidChild).success).toBe(false); + }); + }); + + describe('ChildrenInfoResponseSchema', () => { + test('validates valid children info response', () => { + const validResponse = { + children: [], + more: false, + page: 0 + }; + expect(ChildrenInfoResponseSchema.safeParse(validResponse).success).toBe(true); + }); + + test('rejects negative page number', () => { + const invalidResponse = { + children: [], + more: false, + page: -1 + }; + expect(ChildrenInfoResponseSchema.safeParse(invalidResponse).success).toBe(false); + }); + }); + + describe('InscriptionIDSchema', () => { + test('validates valid inscription ID', () => { + expect(InscriptionIDSchema.safeParse({ id: "abc123" }).success).toBe(true); + }); + + test('validates null ID', () => { + expect(InscriptionIDSchema.safeParse({ id: null }).success).toBe(true); + }); + + test('rejects missing ID field', () => { + expect(InscriptionIDSchema.safeParse({}).success).toBe(false); + }); + }); }); describe('Output Info Schemas', () => { @@ -338,6 +518,43 @@ describe('Schema Validation', () => { }); describe('Rune Schemas', () => { + describe('RuneBalanceSchema', () => { + test('validates valid rune balance', () => { + const validBalance = { + amount: 1000, + divisibility: 8, + symbol: "TEST•RUNE" + }; + expect(RuneBalanceSchema.safeParse(validBalance).success).toBe(true); + }); + + test('rejects negative amount', () => { + const invalidBalance = { + amount: -1000, + divisibility: 8, + symbol: "TEST•RUNE" + }; + expect(RuneBalanceSchema.safeParse(invalidBalance).success).toBe(false); + }); + + test('rejects negative divisibility', () => { + const invalidBalance = { + amount: 1000, + divisibility: -8, + symbol: "TEST•RUNE" + }; + expect(RuneBalanceSchema.safeParse(invalidBalance).success).toBe(false); + }); + + test('rejects missing required fields', () => { + const invalidBalance = { + amount: 1000, + symbol: "TEST•RUNE" + }; + expect(RuneBalanceSchema.safeParse(invalidBalance).success).toBe(false); + }); + }); + describe('RuneInfoSchema', () => { test('validates valid rune', () => { const result = RuneInfoSchema.safeParse(SAMPLE_RUNE); diff --git a/src/types/index.ts b/src/types/index.ts index 26f6faa..4520b80 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -11,6 +11,7 @@ import type { InscriptionsResponseSchema, OutputInfoSchema, RuneInfoSchema, + RuneBalanceSchema, RunesResponseSchema, SatInfoSchema, ServerStatusSchema, @@ -19,19 +20,30 @@ import type { RarityTypeSchema, OutputSchema, OutputTypeSchema, + BlockDetailsSchema, + InscriptionIDSchema, + InscriptionsIDsResponseSchema, + ChildrenInfoResponseSchema, + InscriptionRecursiveSchema, + OutputAssetsSchema, + TransactionHexSchema, + SatRangeSchema, + ChildInfoSchema, } from '../schemas'; /** * Comprehensive information about a Bitcoin address including its balance, outputs, inscriptions, and runes balances. - * */ export type AddressInfo = z.infer; /** - * Detailed block information including height, hash, timestamp, transaction list, and inscription data. - * + * Basic block information including inscriptions and runes. */ export type BlockInfo = z.infer; +/** + * Detailed information about given block. + */ +export type BlockDetails = z.infer; /** * A Bitcoin block hash represented as a hex string. */ @@ -49,6 +61,10 @@ export type Transaction = z.infer; * Extended transaction information including block details, timestamp and inscription data. */ export type TransactionInfo = z.infer; +/** + * Hex-encoded transaction. + */ +export type TransactionHex = z.infer; /** * Transaction input containing previous output reference and witness data. */ @@ -57,12 +73,14 @@ export type Input = z.infer; * Transaction output containing value and script pubkey. */ export type Output = z.infer; - /** - * Information about a specific satoshi including its number, timestamp, - * and rarity classification. + * Information about a specific satoshi including its number, timestamp, and rarity classification. */ export type SatInfo = z.infer; +/** + * A tuple representing a range of satoshis with start and end values. + */ +export type SatRange = z.infer; /** * Special characteristics or properties of a sat (e.g. "cursed", "epic", "burned"). */ @@ -77,23 +95,51 @@ export type RarityType = z.infer; export type OutputType = z.infer; /** * Detailed information about a UTXO including value, script type, and any inscriptions or runes it contains. - * */ export type OutputInfo = z.infer; +/** + * Information about assets held by an UTXO. + */ +export type OutputAssets = z.infer; /** * Comprehensive information about an inscription including its content type, genesis data, location and transfer history. - * */ export type InscriptionInfo = z.infer; /** - * Paginated response containing a list of inscriptions and metadata. + * Comprehensive information about an inscription retrieved from recursive endpoint. + */ +export type InscriptionRecursive = z.infer; +/** + * Paginated response containing a list of inscriptions IDs. */ export type InscriptionsResponse = z.infer; +/** + * Response containing a single inscription ID. + */ +export type InscriptionID = z.infer; +/** + * Paginated response containing a list of inscription IDs + */ +export type InscriptionsIDsResponse = z.infer< + typeof InscriptionsIDsResponseSchema +>; +/** + * Paginated response containing child inscriptions detailed info. + */ +export type ChildrenInfoResponse = z.infer; +/** + * Child inscription info retrieved from recursive endpoint. + */ +export type ChildInfo = z.infer; /** * Basic information about a rune including its symbol and supply details. */ export type RuneInfo = z.infer; +/** + * Basic information about a rune held by an UTXO. + */ +export type RuneBalance = z.infer; /** * Detailed rune information including minting status and parent. */ @@ -105,6 +151,5 @@ export type RunesResponse = z.infer; /** * Current status information about the ordinals server including version, height and indexing progress. - * */ export type ServerStatus = z.infer; From 31cf4b160935913b420591627d575f3edab3fd5b Mon Sep 17 00:00:00 2001 From: gmemez Date: Thu, 6 Feb 2025 17:55:23 +0700 Subject: [PATCH 2/6] generator improvements --- docs/api-docs.json | 1124 +++++++++++++++++---------------- docs/generate.ts | 144 ++--- docs/generateHtml.ts | 6 +- docs/generateMethodsDocs.ts | 153 +++-- docs/generateTypesDocs.ts | 299 ++++----- docs/shared-utils.ts | 263 ++++++++ docs/types.ts | 85 +++ docs/utils/doc-parser.ts | 59 -- docs/utils/zod-type-parser.ts | 59 ++ 9 files changed, 1269 insertions(+), 923 deletions(-) create mode 100644 docs/shared-utils.ts create mode 100644 docs/types.ts delete mode 100644 docs/utils/doc-parser.ts create mode 100644 docs/utils/zod-type-parser.ts diff --git a/docs/api-docs.json b/docs/api-docs.json index d5d8504..de7b190 100644 --- a/docs/api-docs.json +++ b/docs/api-docs.json @@ -1,579 +1,619 @@ { - "classMethods": [ + "methods": [ { "name": "getAddressInfo", + "description": "Retrieves information about a specific address including its outputs, inscriptions, and rune balances.", "parameters": [ { "name": "address", "type": "string", - "description": "" + "description": "Bitcoin address to query." } ], - "description": "Retrieves information about a specific address including its outputs, inscriptions, and rune balances.", "endpoint": "/address/{address}", "httpMethod": "GET", "returnType": "Promise", - "recursive": false - }, - { - "name": "getBlockInfo", - "parameters": [ - { - "name": "heightOrHash", - "type": "number | BlockHash", - "description": "" - } - ], - "description": "Fetches details about a specific block by its height or hash.", - "endpoint": "/block/{heightOrHash}", - "httpMethod": "GET", - "returnType": "Promise", - "recursive": false - }, - { - "name": "getBlockInfoRecursive", - "parameters": [ - { - "name": "heightOrHash", - "type": "number | string", - "description": "" - } - ], - "description": "Gets detailed block information using the recursive endpoint.", - "endpoint": "/r/blockinfo/{heightOrHash}", - "httpMethod": "GET", - "returnType": "Promise", - "recursive": true + "recursive": false, + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" }, { "name": "getBlockCount", - "parameters": [], "description": "Retrieves the total number of blocks in the blockchain.", + "parameters": [], "endpoint": "/blockcount", "httpMethod": "GET", "returnType": "Promise", - "recursive": false + "recursive": false, + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" }, { "name": "getBlockHash", - "parameters": [], "description": "Gets the hash of the latest block.", - "endpoint": "/blockhash", - "httpMethod": "GET", - "returnType": "Promise", - "recursive": false - }, - { - "name": "getBlockHashRecursive", "parameters": [], - "description": "Gets the latest block hash using the recursive endpoint.", - "endpoint": "/r/blockhash", + "endpoint": "/blockhash", "httpMethod": "GET", "returnType": "Promise", - "recursive": true + "recursive": false, + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" }, { "name": "getBlockHashByHeight", + "description": "Gets the hash of a block at the specified height.", "parameters": [ { "name": "height", "type": "number", - "description": "" + "description": "Block height to get hash for" } ], - "description": "Gets the hash of a block at the specified height.", "endpoint": "/blockhash/{height}", "httpMethod": "GET", "returnType": "Promise", - "recursive": false + "recursive": false, + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" }, { "name": "getBlockHashByHeightRecursive", + "description": "Gets the block hash using the recursive endpoint.", "parameters": [ { "name": "height", "type": "number", - "description": "" + "description": "Block height" } ], - "description": "Gets the block hash using the recursive endpoint.", "endpoint": "/r/blockhash/{height}", "httpMethod": "GET", "returnType": "Promise", - "recursive": true + "recursive": true, + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" }, { - "name": "getBlockHeight", + "name": "getBlockHashRecursive", + "description": "Gets the latest block hash using the recursive endpoint.", "parameters": [], + "endpoint": "/r/blockhash", + "httpMethod": "GET", + "returnType": "Promise", + "recursive": true, + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" + }, + { + "name": "getBlockHeight", "description": "Gets the height of the latest block.", + "parameters": [], "endpoint": "/blockheight", "httpMethod": "GET", "returnType": "Promise", - "recursive": false + "recursive": false, + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" }, { "name": "getBlockHeightRecursive", - "parameters": [], "description": "Gets the latest block height using the recursive endpoint.", + "parameters": [], "endpoint": "/r/blockheight", "httpMethod": "GET", "returnType": "Promise", - "recursive": true + "recursive": true, + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" + }, + { + "name": "getBlockInfo", + "description": "Fetches details about a specific block by its height or hash.", + "parameters": [ + { + "name": "heightOrHash", + "type": "any", + "description": "Block height (number) or block hash (string)." + } + ], + "endpoint": "/block/{heightOrHash}", + "httpMethod": "GET", + "returnType": "Promise", + "recursive": false, + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" + }, + { + "name": "getBlockInfoRecursive", + "description": "Gets detailed block information using the recursive endpoint.", + "parameters": [ + { + "name": "heightOrHash", + "type": "string | number", + "description": "Block height or hash" + } + ], + "endpoint": "/r/blockinfo/{heightOrHash}", + "httpMethod": "GET", + "returnType": "Promise", + "recursive": true, + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" }, { "name": "getBlocksLatest", - "parameters": [], "description": "Returns the height of the latest block, the blockhashes of the last 100 blocks, and featured inscriptions from them.", + "parameters": [], "endpoint": "/blocks", "httpMethod": "GET", "returnType": "Promise", - "recursive": false + "recursive": false, + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" }, { "name": "getBlockTime", - "parameters": [], "description": "Gets the timestamp of the latest block.", + "parameters": [], "endpoint": "/blocktime", "httpMethod": "GET", "returnType": "Promise", - "recursive": false + "recursive": false, + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" }, { "name": "getBlockTimeRecursive", - "parameters": [], "description": "Gets block time using the recursive endpoint.", + "parameters": [], "endpoint": "/r/blocktime", "httpMethod": "GET", "returnType": "Promise", - "recursive": true + "recursive": true, + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" }, { - "name": "getInscriptionInfo", + "name": "getChild", + "description": "Gets a specific child inscription of a parent inscription.", "parameters": [ { "name": "id", "type": "string", - "description": "" + "description": "Parent inscription ID" + }, + { + "name": "child", + "type": "number", + "description": "Index of the child inscription" } ], - "description": "Retrieves information about a specific inscription by its ID.", - "endpoint": "/inscription/{id}", + "endpoint": "/inscription/{id}/{child}", "httpMethod": "GET", "returnType": "Promise", - "recursive": false + "recursive": false, + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" }, { - "name": "getInscriptionRecursive", + "name": "getChildren", + "description": "Gets first 100 child inscriptions IDs.", "parameters": [ { "name": "id", "type": "string", - "description": "" + "description": "Parent inscription ID" } ], - "description": "Gets recursive inscription information.", - "endpoint": "/r/inscription/{id}", - "httpMethod": "GET", - "returnType": "Promise", - "recursive": true - }, - { - "name": "getInscriptions", - "parameters": [], - "description": "Gets a list of the 100 most recent inscriptions.", - "endpoint": "/inscriptions", + "endpoint": "/r/children/{id}", "httpMethod": "GET", - "returnType": "Promise", - "recursive": false + "returnType": "Promise", + "recursive": true, + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" }, { - "name": "getInscriptionsByIds", + "name": "getChildrenByPage", + "description": "Gets paginated child inscription IDs.", "parameters": [ { - "name": "ids", - "type": "string[]", - "description": "" - } - ], - "description": "Retrieves information about multiple inscriptions by their IDs.", - "endpoint": "/inscriptions", - "httpMethod": "POST", - "returnType": "Promise", - "recursive": false - }, - { - "name": "getInscriptionsByPage", - "parameters": [ + "name": "id", + "type": "string", + "description": "Parent inscription ID" + }, { "name": "page", "type": "number", - "description": "" + "description": "Page number" } ], - "description": "Gets inscriptions for a specific page number in paginated results.", - "endpoint": "/inscriptions/{page}", + "endpoint": "/r/children/{id}/{page}", "httpMethod": "GET", - "returnType": "Promise", - "recursive": false + "returnType": "Promise", + "recursive": true, + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" }, { - "name": "getInscriptionsByBlock", + "name": "getChildrenInfo", + "description": "Gets details of the first 100 child inscriptions.", "parameters": [ { - "name": "height", - "type": "number", - "description": "" + "name": "id", + "type": "string", + "description": "Parent inscription ID" } ], - "description": "Gets all inscriptions in a specific block.", - "endpoint": "/inscriptions/block/{height}", + "endpoint": "/r/children/{id}/inscriptions", "httpMethod": "GET", - "returnType": "Promise", - "recursive": false + "returnType": "Promise", + "recursive": true, + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" }, { - "name": "getInscriptionOnSat", + "name": "getChildrenInfoByPage", + "description": "Gets paginated detailed child inscription information.", "parameters": [ { - "name": "number", - "type": "number", - "description": "" + "name": "id", + "type": "string", + "description": "Parent inscription ID" }, { - "name": "index", + "name": "page", "type": "number", - "description": "" + "description": "Page number" } ], - "description": "Gets ID of a specific inscription at an index by sat number. The inscription id at index of all inscriptions on a sat. Index may be a negative number to index from the back. 0 being the first and -1 being the most recent for example. Requires index with --index-sats flag.", - "endpoint": "/r/sat/{number}/at/{index}", + "endpoint": "/r/children/{id}/inscriptions/{page}", "httpMethod": "GET", - "returnType": "Promise", - "recursive": true + "returnType": "Promise", + "recursive": true, + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" }, { - "name": "getInscriptionsOnSat", + "name": "getInscriptionInfo", + "description": "Retrieves information about a specific inscription by its ID.", "parameters": [ { - "name": "number", - "type": "number", - "description": "" + "name": "id", + "type": "string", + "description": "Inscription ID" } ], - "description": "Gets the first 100 inscription ids on a sat. Requires index with --index-sats flag.", - "endpoint": "/r/sat/{number}", + "endpoint": "/inscription/{id}", "httpMethod": "GET", - "returnType": "Promise", - "recursive": true + "returnType": "Promise", + "recursive": false, + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" }, { - "name": "getInscriptionsOnSatByPage", + "name": "getInscriptionOnSat", + "description": "Gets ID of a specific inscription at an index by sat number. The inscription id at index of all inscriptions on a sat. Index may be a negative number to index from the back. 0 being the first and -1 being the most recent for example. Requires index with --index-sats flag.", "parameters": [ { "name": "number", "type": "number", - "description": "" + "description": "Satoshi number" }, { - "name": "page", + "name": "index", "type": "number", - "description": "" + "description": "Inscription index" } ], - "description": "Gets paginated inscription ids for a specific satoshi.", - "endpoint": "/r/sat/{number}/{page}", + "endpoint": "/r/sat/{number}/at/{index}", "httpMethod": "GET", - "returnType": "Promise", - "recursive": true + "returnType": "Promise", + "recursive": true, + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" }, { - "name": "getChild", + "name": "getInscriptionRecursive", + "description": "Gets recursive inscription information.", "parameters": [ { "name": "id", "type": "string", - "description": "" - }, - { - "name": "child", - "type": "number", - "description": "" + "description": "Inscription ID" } ], - "description": "Gets a specific child inscription of a parent inscription.", - "endpoint": "/inscription/{id}/{child}", + "endpoint": "/r/inscription/{id}", "httpMethod": "GET", - "returnType": "Promise", - "recursive": false + "returnType": "Promise", + "recursive": true, + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" }, { - "name": "getChildren", - "parameters": [ - { - "name": "id", - "type": "string", - "description": "" - } - ], - "description": "Gets first 100 child inscriptions IDs.", - "endpoint": "/r/children/{id}", + "name": "getInscriptions", + "description": "Gets a list of the 100 most recent inscriptions.", + "parameters": [], + "endpoint": "/inscriptions", "httpMethod": "GET", - "returnType": "Promise", - "recursive": true + "returnType": "Promise", + "recursive": false, + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" }, { - "name": "getChildrenByPage", + "name": "getInscriptionsByBlock", + "description": "Gets all inscriptions in a specific block.", "parameters": [ { - "name": "id", - "type": "string", - "description": "" - }, - { - "name": "page", + "name": "height", "type": "number", - "description": "" + "description": "Block height to fetch inscriptions from" } ], - "description": "Gets paginated child inscription IDs.", - "endpoint": "/r/children/{id}/{page}", + "endpoint": "/inscriptions/block/{height}", "httpMethod": "GET", - "returnType": "Promise", - "recursive": true + "returnType": "Promise", + "recursive": false, + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" }, { - "name": "getChildrenInfo", + "name": "getInscriptionsByIds", + "description": "Retrieves information about multiple inscriptions by their IDs.", "parameters": [ { - "name": "id", - "type": "string", - "description": "" + "name": "ids", + "type": "string[]", + "description": "Array of inscription IDs to fetch" } ], - "description": "Gets details of the first 100 child inscriptions.", - "endpoint": "/r/children/{id}/inscriptions", - "httpMethod": "GET", - "returnType": "Promise", - "recursive": true + "endpoint": "/inscriptions", + "httpMethod": "POST", + "returnType": "Promise", + "recursive": false, + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" }, { - "name": "getChildrenInfoByPage", + "name": "getInscriptionsByPage", + "description": "Gets inscriptions for a specific page number in paginated results.", "parameters": [ - { - "name": "id", - "type": "string", - "description": "" - }, { "name": "page", "type": "number", - "description": "" + "description": "Page number to fetch" } ], - "description": "Gets paginated detailed child inscription information.", - "endpoint": "/r/children/{id}/inscriptions/{page}", + "endpoint": "/inscriptions/{page}", "httpMethod": "GET", - "returnType": "Promise", - "recursive": true + "returnType": "Promise", + "recursive": false, + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" }, { - "name": "getParents", + "name": "getInscriptionsOnSat", + "description": "Gets the first 100 inscription ids on a sat. Requires index with --index-sats flag.", "parameters": [ { - "name": "id", - "type": "string", - "description": "" + "name": "number", + "type": "number", + "description": "Satoshi number" } ], - "description": "Gets parent inscription IDs.", - "endpoint": "/r/parents/{id}", + "endpoint": "/r/sat/{number}", "httpMethod": "GET", - "returnType": "Promise", - "recursive": true + "returnType": "Promise", + "recursive": true, + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" }, { - "name": "getParentsByPage", + "name": "getInscriptionsOnSatByPage", + "description": "Gets paginated inscription ids for a specific satoshi.", "parameters": [ { - "name": "id", - "type": "string", - "description": "" + "name": "number", + "type": "number", + "description": "Satoshi number" }, { "name": "page", "type": "number", - "description": "" + "description": "Page number" } ], - "description": "Gets paginated parent inscription IDs.", - "endpoint": "/r/parents/{id}/{page}", + "endpoint": "/r/sat/{number}/{page}", "httpMethod": "GET", - "returnType": "Promise", - "recursive": true + "returnType": "Promise", + "recursive": true, + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" }, { "name": "getOutput", + "description": "Retrieves information about a specific UTXO.", "parameters": [ { "name": "outpoint", "type": "string", - "description": "" + "description": "Transaction outpoint in format {txid}:{vout}" } ], - "description": "Retrieves information about a specific UTXO.", "endpoint": "/output/{outpoint}", "httpMethod": "GET", "returnType": "Promise", - "recursive": false + "recursive": false, + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" }, { "name": "getOutputAssets", + "description": "Gets assets held by an UTXO.", "parameters": [ { "name": "outpoint", "type": "string", - "description": "" + "description": "Transaction outpoint" } ], - "description": "Gets assets held by an UTXO.", "endpoint": "/r/utxo/{outpoint}", "httpMethod": "GET", "returnType": "Promise", - "recursive": true + "recursive": true, + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" }, { "name": "getOutputs", + "description": "Gets information about multiple UTXOs.", "parameters": [ { "name": "outpoints", "type": "string[]", - "description": "" + "description": "Array of outpoints to fetch" } ], - "description": "Gets information about multiple UTXOs.", "endpoint": "/outputs", "httpMethod": "POST", "returnType": "Promise", - "recursive": false + "recursive": false, + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" }, { "name": "getOutputsByAddress", + "description": "Gets all UTXOs for a specific address, optionally filtered by type.", "parameters": [ { "name": "address", "type": "string", - "description": "" + "description": "Bitcoin address to get outputs for" + }, + { + "name": "type", + "type": "OutputType", + "description": "" + } + ], + "endpoint": "/outputs/{address}", + "httpMethod": "GET", + "returnType": "Promise", + "recursive": false, + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" + }, + { + "name": "getParents", + "description": "Gets parent inscription IDs.", + "parameters": [ + { + "name": "id", + "type": "string", + "description": "Child inscription ID" + } + ], + "endpoint": "/r/parents/{id}", + "httpMethod": "GET", + "returnType": "Promise", + "recursive": true, + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" + }, + { + "name": "getParentsByPage", + "description": "Gets paginated parent inscription IDs.", + "parameters": [ + { + "name": "id", + "type": "string", + "description": "Child inscription ID" }, { - "name": "type", - "type": "OutputType", - "description": "" + "name": "page", + "type": "number", + "description": "Page number" } ], - "description": "Gets all UTXOs for a specific address, optionally filtered by type.", - "endpoint": "/outputs/{address}", + "endpoint": "/r/parents/{id}/{page}", "httpMethod": "GET", - "returnType": "Promise", - "recursive": false + "returnType": "Promise", + "recursive": true, + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" }, { "name": "getRune", + "description": "Gets information about a specific rune by name.", "parameters": [ { "name": "name", "type": "string", - "description": "" + "description": "Rune name" } ], - "description": "Gets information about a specific rune by name.", "endpoint": "/rune/{name}", "httpMethod": "GET", "returnType": "Promise", - "recursive": false - }, - { - "name": "getRunesLatest", - "parameters": [], - "description": "Gets a list of the 100 most recent runes.", - "endpoint": "/runes", - "httpMethod": "GET", - "returnType": "Promise", - "recursive": false + "recursive": false, + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" }, { "name": "getRunesByPage", + "description": "Gets runes for a specific page number in paginated results.", "parameters": [ { "name": "page", "type": "number", - "description": "" + "description": "Page number to fetch" } ], - "description": "Gets runes for a specific page number in paginated results.", "endpoint": "/runes/{page}", "httpMethod": "GET", "returnType": "Promise", - "recursive": false + "recursive": false, + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" + }, + { + "name": "getRunesLatest", + "description": "Gets a list of the 100 most recent runes.", + "parameters": [], + "endpoint": "/runes", + "httpMethod": "GET", + "returnType": "Promise", + "recursive": false, + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" }, { "name": "getSat", + "description": "Gets information about a specific satoshi by its number.", "parameters": [ { "name": "number", "type": "number", - "description": "" + "description": "Satoshi number" } ], - "description": "Gets information about a specific satoshi by its number.", "endpoint": "/sat/{number}", "httpMethod": "GET", "returnType": "Promise", - "recursive": false + "recursive": false, + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" + }, + { + "name": "getServerStatus", + "description": "Gets the current server status and information.", + "parameters": [], + "endpoint": "/status", + "httpMethod": "GET", + "returnType": "Promise", + "recursive": false, + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" }, { "name": "getTransaction", + "description": "Gets information about a specific transaction.", "parameters": [ { "name": "txId", "type": "string", - "description": "" + "description": "Transaction ID" } ], - "description": "Gets information about a specific transaction.", "endpoint": "/tx/{txId}", "httpMethod": "GET", "returnType": "Promise", - "recursive": false + "recursive": false, + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" }, { "name": "getTransactionHex", + "description": "Gets hex transaction data.", "parameters": [ { "name": "txid", "type": "string", - "description": "" + "description": "Transaction ID" } ], - "description": "Gets hex transaction data.", "endpoint": "/r/tx/{txid}", "httpMethod": "GET", "returnType": "Promise", - "recursive": true - }, - { - "name": "getServerStatus", - "parameters": [], - "description": "Gets the current server status and information.", - "endpoint": "/status", - "httpMethod": "GET", - "returnType": "Promise", - "recursive": false + "recursive": true, + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" } ], - "exportedTypes": [ + "types": [ { "name": "AddressInfo", - "type": "object", + "kind": "object", "description": "Comprehensive information about a Bitcoin address including its balance, outputs, inscriptions, and runes balances.", "properties": [ { @@ -597,18 +637,48 @@ "description": "" } ], - "sourceFile": "address.ts" + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/schemas/address.ts" }, { - "name": "BlockInfo", - "type": "object", - "description": "Basic block information including inscriptions and runes.", + "name": "BlockDetails", + "kind": "object", + "description": "Detailed information about given block.", "properties": [ { - "name": "best_height", + "name": "average_fee", "type": "number", "description": "" }, + { + "name": "average_fee_rate", + "type": "number", + "description": "" + }, + { + "name": "bits", + "type": "number", + "description": "" + }, + { + "name": "chainwork", + "type": "string", + "description": "" + }, + { + "name": "confirmations", + "type": "number", + "description": "" + }, + { + "name": "difficulty", + "type": "number", + "description": "" + }, + { + "name": "feerate_percentiles", + "type": "number[]", + "description": "" + }, { "name": "hash", "type": "BlockHash", @@ -620,163 +690,233 @@ "description": "" }, { - "name": "inscriptions", - "type": "string[]", + "name": "max_fee", + "type": "number", "description": "" }, { - "name": "runes", - "type": "string[]", + "name": "max_fee_rate", + "type": "number", "description": "" }, { - "name": "target", - "type": "string", + "name": "max_tx_size", + "type": "number", "description": "" }, { - "name": "transactions", - "type": "Transaction[]", + "name": "median_fee", + "type": "number", "description": "" - } - ], - "sourceFile": "block.ts" - }, - { - "name": "BlocksResponse", - "type": "object", - "description": "Paginated response containing a list of recent blocks and metadata.", - "properties": [ + }, { - "name": "blocks", - "type": "BlockHash[]", + "name": "median_time", + "type": "number | null", "description": "" }, { - "name": "featured_blocks", - "type": "Record", + "name": "merkle_root", + "type": "string", "description": "" }, { - "name": "last", + "name": "min_fee", "type": "number", "description": "" - } - ], - "sourceFile": "block.ts" - }, - { - "name": "BlockDetails", - "type": "object", - "description": "Detailed information about given block.", - "properties": [ + }, { - "name": "average_fee", + "name": "min_fee_rate", "type": "number", "description": "" }, { - "name": "average_fee_rate", + "name": "next_block", + "type": "BlockHash | null", + "description": "" + }, + { + "name": "nonce", "type": "number", "description": "" }, { - "name": "bits", + "name": "previous_block", + "type": "BlockHash | null", + "description": "" + }, + { + "name": "subsidy", "type": "number", "description": "" }, { - "name": "chainwork", + "name": "target", "type": "string", "description": "" }, { - "name": "confirmations", + "name": "timestamp", "type": "number", "description": "" }, { - "name": "difficulty", + "name": "total_fee", "type": "number", "description": "" }, { - "name": "feerate_percentiles", - "type": "number[]", + "name": "total_size", + "type": "number", "description": "" }, { - "name": "hash", - "type": "BlockHash", + "name": "total_weight", + "type": "number", "description": "" }, { - "name": "height", + "name": "transaction_count", "type": "number", "description": "" }, { - "name": "max_fee", + "name": "version", "type": "number", "description": "" - }, + } + ], + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/schemas/block.ts" + }, + { + "name": "BlockInfo", + "kind": "object", + "description": "Basic block information including inscriptions and runes.", + "properties": [ { - "name": "max_fee_rate", + "name": "best_height", "type": "number", "description": "" }, { - "name": "max_tx_size", - "type": "number", + "name": "hash", + "type": "BlockHash", "description": "" }, { - "name": "median_fee", + "name": "height", "type": "number", "description": "" }, { - "name": "median_time", - "type": "number | null", + "name": "inscriptions", + "type": "string[]", "description": "" }, { - "name": "merkle_root", + "name": "runes", + "type": "string[]", + "description": "" + }, + { + "name": "target", "type": "string", "description": "" }, { - "name": "min_fee", + "name": "transactions", + "type": "Transaction[]", + "description": "" + } + ], + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/schemas/block.ts" + }, + { + "name": "BlocksResponse", + "kind": "object", + "description": "Paginated response containing a list of recent blocks and metadata.", + "properties": [ + { + "name": "blocks", + "type": "BlockHash[]", + "description": "" + }, + { + "name": "featured_blocks", + "type": "Record", + "description": "" + }, + { + "name": "last", + "type": "number", + "description": "" + } + ], + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/schemas/block.ts" + }, + { + "name": "CharmType", + "kind": "enum", + "description": "Special characteristics or properties of a sat (e.g. \"cursed\", \"epic\", \"burned\").", + "values": [ + "burned", + "coin", + "cursed", + "epic", + "legendary", + "lost", + "mythic", + "nineball", + "palindrome", + "rare", + "reinscription", + "unbound", + "uncommon", + "vindicated" + ], + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/schemas/inscription.ts" + }, + { + "name": "ChildInfo", + "kind": "object", + "description": "Child inscription info retrieved from recursive endpoint.", + "properties": [ + { + "name": "charms", + "type": "CharmType[]", + "description": "" + }, + { + "name": "fee", "type": "number", "description": "" }, { - "name": "min_fee_rate", + "name": "height", "type": "number", "description": "" }, { - "name": "next_block", - "type": "BlockHash | null", + "name": "id", + "type": "string", "description": "" }, { - "name": "nonce", + "name": "number", "type": "number", "description": "" }, { - "name": "previous_block", - "type": "BlockHash | null", + "name": "output", + "type": "string", "description": "" }, { - "name": "subsidy", + "name": "sat", "type": "number", "description": "" }, { - "name": "target", + "name": "satpoint", "type": "string", "description": "" }, @@ -784,60 +924,77 @@ "name": "timestamp", "type": "number", "description": "" + } + ], + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/schemas/inscription.ts" + }, + { + "name": "ChildrenInfoResponse", + "kind": "object", + "description": "Paginated response containing child inscriptions detailed info.", + "properties": [ + { + "name": "children", + "type": "ChildInfo[]", + "description": "" }, { - "name": "total_fee", - "type": "number", + "name": "more", + "type": "boolean", "description": "" }, { - "name": "total_size", + "name": "page", "type": "number", "description": "" + } + ], + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/schemas/inscription.ts" + }, + { + "name": "Input", + "kind": "object", + "description": "Transaction input containing previous output reference and witness data.", + "properties": [ + { + "name": "previous_output", + "type": "string", + "description": "" }, { - "name": "total_weight", - "type": "number", + "name": "script_sig", + "type": "string", "description": "" }, { - "name": "transaction_count", + "name": "sequence", "type": "number", "description": "" }, { - "name": "version", - "type": "number", + "name": "witness", + "type": "string[]", "description": "" } ], - "sourceFile": "block.ts" + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/schemas/transaction.ts" }, { - "name": "CharmType", - "type": "enum", - "description": "Special characteristics or properties of a sat (e.g. \"cursed\", \"epic\", \"burned\").", - "values": [ - "burned", - "coin", - "cursed", - "epic", - "legendary", - "lost", - "mythic", - "nineball", - "palindrome", - "rare", - "reinscription", - "unbound", - "uncommon", - "vindicated" + "name": "InscriptionID", + "kind": "object", + "description": "Response containing a single inscription ID.", + "properties": [ + { + "name": "id", + "type": "string | null", + "description": "" + } ], - "sourceFile": "inscription.ts" + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/schemas/inscription.ts" }, { "name": "InscriptionInfo", - "type": "object", + "kind": "object", "description": "Comprehensive information about an inscription including its content type, genesis data, location and transfer history.", "properties": [ { @@ -941,11 +1098,11 @@ "description": "" } ], - "sourceFile": "inscription.ts" + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/schemas/inscription.ts" }, { "name": "InscriptionRecursive", - "type": "object", + "kind": "object", "description": "Comprehensive information about an inscription retrieved from recursive endpoint.", "properties": [ { @@ -1019,12 +1176,12 @@ "description": "" } ], - "sourceFile": "inscription.ts" + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/schemas/inscription.ts" }, { - "name": "InscriptionsResponse", - "type": "object", - "description": "Paginated response containing a list of inscriptions IDs.", + "name": "InscriptionsIDsResponse", + "kind": "object", + "description": "Paginated response containing a list of inscription IDs", "properties": [ { "name": "ids", @@ -1037,17 +1194,17 @@ "description": "" }, { - "name": "page_index", + "name": "page", "type": "number", "description": "" } ], - "sourceFile": "inscription.ts" + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/schemas/inscription.ts" }, { - "name": "InscriptionsIDsResponse", - "type": "object", - "description": "Paginated response containing a list of inscription IDs", + "name": "InscriptionsResponse", + "kind": "object", + "description": "Paginated response containing a list of inscriptions IDs.", "properties": [ { "name": "ids", @@ -1060,117 +1217,62 @@ "description": "" }, { - "name": "page", + "name": "page_index", "type": "number", "description": "" } ], - "sourceFile": "inscription.ts" + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/schemas/inscription.ts" }, { - "name": "ChildInfo", - "type": "object", - "description": "Child inscription info retrieved from recursive endpoint.", + "name": "Output", + "kind": "object", + "description": "Transaction output containing value and script pubkey.", "properties": [ { - "name": "charms", - "type": "CharmType[]", - "description": "" - }, - { - "name": "fee", - "type": "number", - "description": "" - }, - { - "name": "height", - "type": "number", - "description": "" - }, - { - "name": "id", - "type": "string", - "description": "" - }, - { - "name": "number", - "type": "number", - "description": "" - }, - { - "name": "output", - "type": "string", - "description": "" - }, - { - "name": "sat", - "type": "number", - "description": "" - }, - { - "name": "satpoint", + "name": "script_pubkey", "type": "string", "description": "" }, { - "name": "timestamp", + "name": "value", "type": "number", "description": "" } ], - "sourceFile": "inscription.ts" + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/schemas/transaction.ts" }, { - "name": "ChildrenInfoResponse", - "type": "object", - "description": "Paginated response containing child inscriptions detailed info.", + "name": "OutputAssets", + "kind": "object", + "description": "Information about assets held by an UTXO.", "properties": [ { - "name": "children", - "type": "ChildInfo[]", + "name": "inscriptions", + "type": "string[] | null", "description": "" }, { - "name": "more", - "type": "boolean", + "name": "runes", + "type": "Record | null", "description": "" }, { - "name": "page", - "type": "number", + "name": "sat_ranges", + "type": "SatRange[] | null", "description": "" - } - ], - "sourceFile": "inscription.ts" - }, - { - "name": "InscriptionID", - "type": "object", - "description": "Response containing a single inscription ID.", - "properties": [ + }, { - "name": "id", - "type": "string | null", + "name": "value", + "type": "number", "description": "" } ], - "sourceFile": "inscription.ts" - }, - { - "name": "OutputType", - "type": "enum", - "description": "Type of UTXO output (e.g. \"plain\", \"inscription\", \"rune\").", - "values": [ - "any", - "cardinal", - "inscribed", - "runic" - ], - "sourceFile": "output.ts" + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/schemas/output.ts" }, { "name": "OutputInfo", - "type": "object", + "kind": "object", "description": "Detailed information about a UTXO including value, script type, and any inscriptions or runes it contains.", "properties": [ { @@ -1224,39 +1326,37 @@ "description": "" } ], - "sourceFile": "output.ts" + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/schemas/output.ts" }, { - "name": "OutputAssets", - "type": "object", - "description": "Information about assets held by an UTXO.", - "properties": [ - { - "name": "inscriptions", - "type": "string[] | null", - "description": "" - }, - { - "name": "runes", - "type": "Record | null", - "description": "" - }, - { - "name": "sat_ranges", - "type": "SatRange[] | null", - "description": "" - }, - { - "name": "value", - "type": "number", - "description": "" - } + "name": "OutputType", + "kind": "enum", + "description": "Type of UTXO output (e.g. \"plain\", \"inscription\", \"rune\").", + "values": [ + "any", + "cardinal", + "inscribed", + "runic" + ], + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/schemas/output.ts" + }, + { + "name": "RarityType", + "kind": "enum", + "description": "Classification of sat rarity (e.g. \"common\", \"uncommon\", \"rare\", \"epic\", \"legendary\").", + "values": [ + "common", + "epic", + "legendary", + "mythic", + "rare", + "uncommon" ], - "sourceFile": "output.ts" + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/schemas/sat.ts" }, { "name": "RuneBalance", - "type": "object", + "kind": "object", "description": "Basic information about a rune held by an UTXO.", "properties": [ { @@ -1275,11 +1375,11 @@ "description": "" } ], - "sourceFile": "rune.ts" + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/schemas/rune.ts" }, { "name": "RuneInfo", - "type": "object", + "kind": "object", "description": "Basic information about a rune including its symbol and supply details.", "properties": [ { @@ -1343,11 +1443,11 @@ "description": "" } ], - "sourceFile": "rune.ts" + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/schemas/rune.ts" }, { "name": "RuneResponse", - "type": "object", + "kind": "object", "description": "Detailed rune information including minting status and parent.", "properties": [ { @@ -1371,11 +1471,11 @@ "description": "" } ], - "sourceFile": "rune.ts" + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/schemas/rune.ts" }, { "name": "RunesResponse", - "type": "object", + "kind": "object", "description": "Paginated response containing a list of runes and metadata.", "properties": [ { @@ -1399,25 +1499,11 @@ "description": "" } ], - "sourceFile": "rune.ts" - }, - { - "name": "RarityType", - "type": "enum", - "description": "Classification of sat rarity (e.g. \"common\", \"uncommon\", \"rare\", \"epic\", \"legendary\").", - "values": [ - "common", - "epic", - "legendary", - "mythic", - "rare", - "uncommon" - ], - "sourceFile": "sat.ts" + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/schemas/rune.ts" }, { "name": "SatInfo", - "type": "object", + "kind": "object", "description": "Information about a specific satoshi including its number, timestamp, and rarity classification.", "properties": [ { @@ -1501,11 +1587,11 @@ "description": "" } ], - "sourceFile": "sat.ts" + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/schemas/sat.ts" }, { "name": "ServerStatus", - "type": "object", + "kind": "object", "description": "Current status information about the ordinals server including version, height and indexing progress.", "properties": [ { @@ -1589,57 +1675,29 @@ "description": "" } ], - "sourceFile": "status.ts" + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/schemas/status.ts" }, { - "name": "Input", - "type": "object", - "description": "Transaction input containing previous output reference and witness data.", + "name": "Time", + "kind": "object", + "description": "Type defined in /Users/gole/Desktop/ord-js/ord-js/src/schemas/status.ts", "properties": [ { - "name": "previous_output", - "type": "string", - "description": "" - }, - { - "name": "script_sig", - "type": "string", - "description": "" - }, - { - "name": "sequence", + "name": "nanos", "type": "number", "description": "" }, { - "name": "witness", - "type": "string[]", - "description": "" - } - ], - "sourceFile": "transaction.ts" - }, - { - "name": "Output", - "type": "object", - "description": "Transaction output containing value and script pubkey.", - "properties": [ - { - "name": "script_pubkey", - "type": "string", - "description": "" - }, - { - "name": "value", + "name": "secs", "type": "number", "description": "" } ], - "sourceFile": "transaction.ts" + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/schemas/status.ts" }, { "name": "Transaction", - "type": "object", + "kind": "object", "description": "Bitcoin transaction data including version, locktime, inputs and outputs.", "properties": [ { @@ -1663,11 +1721,11 @@ "description": "" } ], - "sourceFile": "transaction.ts" + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/schemas/transaction.ts" }, { "name": "TransactionInfo", - "type": "object", + "kind": "object", "description": "Extended transaction information including block details, timestamp and inscription data.", "properties": [ { @@ -1696,7 +1754,7 @@ "description": "" } ], - "sourceFile": "transaction.ts" + "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/schemas/transaction.ts" } ] } \ No newline at end of file diff --git a/docs/generate.ts b/docs/generate.ts index 1c39f66..6eb7857 100644 --- a/docs/generate.ts +++ b/docs/generate.ts @@ -1,50 +1,30 @@ -import * as ts from 'typescript'; -import * as fs from 'fs'; import * as path from 'path'; -import { CustomType, extractZodSchema } from './generateTypesDocs'; -import { getMethodDocs, type MethodDoc } from './generateMethodsDocs'; - -interface Documentation { - classMethods: MethodDoc[]; - exportedTypes: CustomType[]; -} +import { Documentation, MethodDocumentation, TypeDocumentation } from './types'; +import { generateTypeDocs } from './generateTypesDocs'; +import { generateMethodDocs } from './generateMethodsDocs'; +import { + getAllFiles, + createTSProgram, + writeDocs +} from './shared-utils'; function generateDocs(sourceFiles: string[]): Documentation { - const options: ts.CompilerOptions = { - target: ts.ScriptTarget.ESNext, - module: ts.ModuleKind.ESNext, - allowJs: true, - checkJs: true, - noEmit: true, - types: ['node'], - skipLibCheck: true, - }; - - const program = ts.createProgram(sourceFiles, options); - const methods: MethodDoc[] = []; - - // Sort source files by their base names - const sortedFiles = [...sourceFiles].sort((a, b) => - path.basename(a).localeCompare(path.basename(b)) - ); - - // Use OrderedMap to maintain file ordering - const typesByFile = new Map(); - - // First pass: collect types maintaining file order - for (const sourceFile of sortedFiles) { - const fileName = sourceFile; + const program = createTSProgram(sourceFiles); + const methods: MethodDocumentation[] = []; + const typesByFile = new Map(); + // First pass: collect types + for (const sourceFile of program.getSourceFiles()) { + const fileName = sourceFile.fileName; - if (!fileName.endsWith('.ts') || fileName.includes('node_modules')) { + if (fileName.includes('node_modules')) { continue; } - const content = fs.readFileSync(fileName, 'utf8'); - - if (content.includes('z.object') || content.includes('z.enum')) { - const extracted = extractZodSchema(content, path.basename(fileName)); - if (extracted.length > 0) { - typesByFile.set(fileName, extracted); + if (sourceFile.getText().includes('z.object') || + sourceFile.getText().includes('z.enum')) { + const types = generateTypeDocs(sourceFile, program); + if (types.length > 0) { + typesByFile.set(fileName, types); } } } @@ -53,75 +33,49 @@ function generateDocs(sourceFiles: string[]): Documentation { for (const sourceFile of program.getSourceFiles()) { const fileName = sourceFile.fileName; - if (!fileName.endsWith('.ts') || fileName.includes('node_modules')) { + if (fileName.includes('node_modules')) { continue; } - function visit(node: ts.Node) { - if (ts.isClassDeclaration(node)) { - - node.members.forEach(member => { - if (ts.isMethodDeclaration(member)) { - try { - const doc = getMethodDocs(member, sourceFile); - if (doc) { - methods.push(doc); - } - } catch (error) { - console.error('Error processing method:', error); - } - } - }); - } - - ts.forEachChild(node, visit); - } - - visit(sourceFile); + methods.push(...generateMethodDocs(sourceFile, program)); } - // Combine types in file order - const allTypes: CustomType[] = []; - for (const [file, types] of typesByFile.entries()) { - allTypes.push(...types); - } + // Combine all types preserving file order + const allTypes = Array.from(typesByFile.values()).flat(); return { - classMethods: methods, - exportedTypes: allTypes + methods: methods.sort((a, b) => a.name.localeCompare(b.name)), + types: allTypes.sort((a, b) => a.name.localeCompare(b.name)) }; } -// Ensure the docs directory exists -const docsDir = path.join(process.cwd(), 'docs'); -if (!fs.existsSync(docsDir)) { - fs.mkdirSync(docsDir); -} +// Main execution +const SOURCE_DIR = './src'; +const DOCS_DIR = path.join(process.cwd(), 'docs'); -// Generate documentation -const sourceDir = './src'; +// Get source files const sourceFiles = [ - ...fs.readdirSync(sourceDir) - .filter(file => file.endsWith('.ts')) - .map(file => path.join(sourceDir, file)), - ...getAllFiles(path.join(sourceDir, 'schemas')) - .filter(file => file.endsWith('.ts')) -].sort((a, b) => path.basename(a).localeCompare(path.basename(b))); // Sort all source files + ...getAllFiles({ + sourceDir: SOURCE_DIR, + includeExtensions: ['.ts'] + }), + ...getAllFiles({ + sourceDir: path.join(SOURCE_DIR, 'schemas'), + includeExtensions: ['.ts'], + }), + ...getAllFiles({ + sourceDir: path.join(SOURCE_DIR, 'types'), + includeExtensions: ['.ts'], + }) +]; +// Generate documentation const docs = generateDocs(sourceFiles); -fs.writeFileSync( - path.join(docsDir, 'api-docs.json'), - JSON.stringify(docs, null, 2) +// Write the documentation to file +writeDocs( + path.join(DOCS_DIR, 'api-docs.json'), + docs ); -function getAllFiles(dir: string): string[] { - if (!fs.existsSync(dir)) { - return []; - } - const files = fs.readdirSync(dir); - return files.flatMap(file => { - const fullPath = path.join(dir, file); - return fs.statSync(fullPath).isDirectory() ? getAllFiles(fullPath) : fullPath; - }); -} \ No newline at end of file +console.log('Documentation generated successfully at docs/api-docs.json'); \ No newline at end of file diff --git a/docs/generateHtml.ts b/docs/generateHtml.ts index db1395e..c938514 100644 --- a/docs/generateHtml.ts +++ b/docs/generateHtml.ts @@ -9,7 +9,7 @@ function generateHtml() { const scriptsContent = fs.readFileSync('docs/scripts.js', 'utf-8'); const apiDocs = JSON.parse(fs.readFileSync('docs/api-docs.json', 'utf-8')); const cssContent = fs.readFileSync('docs/styles.css', 'utf-8'); - const typeNames = new Set(apiDocs.exportedTypes.map(type => type.name)); + const typeNames = new Set(apiDocs.types.map(type => type.name)); function createTypeLink(type) { const escaped = type.replace(//g, '>'); @@ -100,7 +100,7 @@ function generateHtml() {
- ${apiDocs.classMethods.map(method => ` + ${apiDocs.methods.map(method => `
@@ -142,7 +142,7 @@ function generateHtml() {
- ${apiDocs.exportedTypes.map(type => ` + ${apiDocs.types.map(type => `

${type.name}

diff --git a/docs/generateMethodsDocs.ts b/docs/generateMethodsDocs.ts index 951b520..db0e580 100644 --- a/docs/generateMethodsDocs.ts +++ b/docs/generateMethodsDocs.ts @@ -1,49 +1,111 @@ import * as ts from 'typescript'; -import { extractDocComment, parseDocComment } from './utils/doc-parser'; +import { MethodDocumentation } from './types'; +import { extractJSDoc, visitNodes } from './shared-utils'; import api from '../src/api'; -export interface MethodDoc { - name: string; - parameters: { - name: string; - type: string; - description: string; - }[]; - description: string; +/** + * Generates documentation for all methods in a source file + */ +export function generateMethodDocs( + sourceFile: ts.SourceFile, + program: ts.Program +): MethodDocumentation[] { + const methods: MethodDocumentation[] = []; + const typeChecker = program.getTypeChecker(); + + // Extract all method documentation from the file + const methodDocumentation = extractJSDoc( + sourceFile.fileName, + node => ts.isMethodDeclaration(node) + ); + + // Process each documented method + methodDocumentation.forEach((docs, identifier) => { + const methodName = identifier.split(':')[1]; + + if (!isValidMethod(methodName)) { + return; + } + + // Find the actual method node + visitNodes(sourceFile, (node) => { + if (ts.isMethodDeclaration(node) && + (node.name as ts.Identifier).text === methodName) { + + const { parameters, endpoint, httpMethod } = extractMethodInfo(node, typeChecker); + + methods.push({ + name: methodName, + description: docs.description, + parameters: parameters.map(param => ({ + ...param, + description: docs.params[param.name] || '' + })), + endpoint, + httpMethod, + returnType: node.type?.getText(sourceFile) || 'Promise', + recursive: endpoint.startsWith('/r/'), + sourceFile: sourceFile.fileName + }); + } + }); + }); + + return methods; +} + +/** + * Checks if a method should be documented + */ +function isValidMethod(methodName: string): boolean { + return Boolean( + methodName && + !methodName.startsWith('_') && + !['fetch', 'fetchPost'].includes(methodName) + ); +} + +interface MethodInfo { + parameters: Array<{name: string; type: string}>; endpoint: string; httpMethod: 'GET' | 'POST'; - returnType: string; - recursive: boolean; } -export function getMethodDocs(node: ts.MethodDeclaration, sourceFile: ts.SourceFile): MethodDoc | null { - const nameIdentifier = node.name as ts.Identifier; - const name = nameIdentifier.escapedText.toString(); - - if (!name || name.startsWith('_') || ['fetch', 'fetchPost'].includes(name)) { - return null; - } +function extractMethodInfo( + methodNode: ts.MethodDeclaration, + typeChecker: ts.TypeChecker +): MethodInfo { + const parameters = methodNode.parameters.map(param => ({ + name: (param.name as ts.Identifier).escapedText.toString(), + type: param.type + ? typeChecker.typeToString(typeChecker.getTypeFromTypeNode(param.type)) + : 'any' + })); - const comment = extractDocComment(node, sourceFile); - const docInfo = parseDocComment(comment); + const httpMethod = methodNode.getText().includes('this.fetchPost') ? 'POST' : 'GET'; + const methodName = (methodNode.name as ts.Identifier).escapedText.toString(); + const paramNames = parameters.map(p => p.name); + const endpoint = buildEndpoint(methodName, paramNames); - const endpoint = (() => { - const pathFunction = api[name]; - if (!pathFunction) return ''; + return { + parameters, + endpoint, + httpMethod + }; +} - if (typeof pathFunction === 'string') { - return pathFunction; - } +function buildEndpoint(methodName: string, paramNames: string[]): string { + if (api[methodName] && typeof api[methodName] === 'string') { + return api[methodName]; + } - const params = node.parameters.map(p => - (p.name as ts.Identifier).escapedText.toString() - ); - + const pathFunction = api[methodName]; + if (typeof pathFunction === 'function') { const functionStr = pathFunction.toString(); const urlMatch = functionStr.match(/['"`](.*?)['"`]/); if (urlMatch) { let url = urlMatch[1]; - params.forEach(param => { + paramNames.forEach(param => { url = url.replace( new RegExp(`\\$\\{${param}\\}`, 'g'), `{${param}}` @@ -51,32 +113,7 @@ export function getMethodDocs(node: ts.MethodDeclaration, sourceFile: ts.SourceF }); return url; } - return ''; - })(); - - const parameters = node.parameters.map(param => { - const paramName = (param.name as ts.Identifier).escapedText.toString(); - const paramType = param.type - ? sourceFile.text.slice(param.type.pos, param.type.end).trim() - : 'any'; - - return { - name: paramName, - type: paramType, - description: docInfo.params[paramName] || '' - }; - }); - - const methodText = sourceFile.text.slice(node.pos, node.end); - const httpMethod = methodText.includes('this.fetchPost') ? 'POST' : 'GET'; + } - return { - name, - parameters, - description: docInfo.description, - endpoint, - httpMethod, - returnType: node.type?.getText(sourceFile) || 'Promise', - recursive: endpoint.startsWith('/r/') - }; + return ''; } \ No newline at end of file diff --git a/docs/generateTypesDocs.ts b/docs/generateTypesDocs.ts index 8a438c0..abf1e44 100644 --- a/docs/generateTypesDocs.ts +++ b/docs/generateTypesDocs.ts @@ -1,197 +1,146 @@ -import * as fs from 'fs'; -import * as path from 'path'; +import * as ts from 'typescript'; +import { TypeDocumentation, TypeProperty } from './types'; +import { parseZodType } from './utils/zod-type-parser'; +import { extractJSDoc } from './shared-utils'; -interface Property { - name: string; - type: string; - description: string; -} - -export interface CustomType { - name: string; - type: 'enum' | 'object'; - description: string; - properties?: Property[]; - values?: string[]; - sourceFile: string; -} - -function parseZodType(zodType: string): string { - const typeMap = { - 'z.string()': 'string', - 'z.number()': 'number', - 'z.boolean()': 'boolean' - }; - - const type = zodType.trim(); +export function generateTypeDocs( + sourceFile: ts.SourceFile, + program: ts.Program +): TypeDocumentation[] { + const types: TypeDocumentation[] = []; - if (type.endsWith('Schema')) { - return type.replace('Schema', ''); - } - - if (type.includes('.nullable()')) { - const baseType = type.replace('.nullable()', ''); - return `${parseZodType(baseType)} | null`; - } - - for (const [key, baseType] of Object.entries(typeMap)) { - if (type.startsWith(key)) { - return baseType; + // First collect all schema names from this file + const schemaNames: string[] = []; + ts.forEachChild(sourceFile, node => { + if (ts.isVariableStatement(node)) { + const declaration = node.declarationList.declarations[0]; + if (ts.isIdentifier(declaration.name) && + declaration.name.text.endsWith('Schema')) { + schemaNames.push(declaration.name.text); + } } + }); + + if (schemaNames.length === 0) { + return []; } - - if (type.startsWith('z.array')) { - const innerMatch = type.match(/z\.array\((.*)\)/); - if (!innerMatch) return 'unknown[]'; - return `${parseZodType(innerMatch[1])}[]`; - } - - if (type.startsWith('z.record')) { - const matches = type.match(/z\.record\((.*?),\s*([\s\S]*?)\)(?![\s\S]*\)$)/); - if (!matches) return 'Record'; - const [_, keyType, valueType] = matches; - const parsedValueType = parseZodType(valueType.trim()); - const parsedKeyType = parseZodType(keyType.trim()); - - return `Record<${parsedKeyType}, ${parsedValueType}>`; - } - - if (type.startsWith('z.tuple')) { - const innerMatch = type.match(/z\.tuple\(\[(.*)\]\)/); - if (!innerMatch) return '[unknown]'; - const types = innerMatch[1].split(',').map(t => parseZodType(t.trim())); - return `[${types.join(', ')}]`; - } - - if (type.includes('z.enum')) { - return type.match(/\[(.*?)\]/)?.[1] - .split(',') - .map(v => v.trim().replace(/['"]/g, '')) - .join(' | ') || 'enum'; - } - - return type.replace('z.', ''); -} -function findTypeDescription(typeName: string, typeFileContent: string): string { - const regex = new RegExp( - `\\/\\*\\*([^*]*\\*+(?:[^/*][^*]*\\*+)*)\\/\\s*export\\s+type\\s+${typeName}\\b`, - 'g' + // Find types/index.ts file for documentation + const typesFile = program.getSourceFiles().find(sf => + sf.fileName.includes('types/index.ts') ); - - const match = regex.exec(typeFileContent); - if (!match) return ''; - - return match[1] - .split('\n') - .map(line => line.trim() - .replace(/^\*\s*/, '') - .replace(/\s*\*\/$/, '') - ) - .filter(Boolean) - .join(' ') - .trim(); -} -export function extractZodSchema(schemaContent: string, filename: string): CustomType[] { - let typeFileContent = ''; - try { - const typeFilePath = path.join(process.cwd(), 'src', 'types', 'index.ts'); - if (fs.existsSync(typeFilePath)) { - typeFileContent = fs.readFileSync(typeFilePath, 'utf8'); - } - } catch (error) { - console.warn('Could not read types file:', error); - } + // Get documentation from types/index.ts + const typeDocumentation = typesFile + ? extractJSDoc( + typesFile.fileName, + node => ts.isTypeAliasDeclaration(node) && + schemaNames.some(schema => + node.name.text === schema.replace('Schema', '') + ) + ) + : new Map(); - const schemaRegex = /export\s+const\s+(\w+Schema)\s*=\s*z\.([\s\S]*?);(?=\s*(?:export|$))/g; - const types: CustomType[] = []; - let match; + // Process schemas with documentation + ts.forEachChild(sourceFile, node => { + if (!ts.isVariableStatement(node)) return; - while ((match = schemaRegex.exec(schemaContent)) !== null) { - const [fullMatch, schemaName, definition] = match; + const declaration = node.declarationList.declarations[0]; + if (!ts.isIdentifier(declaration.name) || + !declaration.name.text.endsWith('Schema')) { + return; + } + + const schemaName = declaration.name.text; const typeName = schemaName.replace('Schema', ''); - const description = findTypeDescription(typeName, typeFileContent); + const docs = typeDocumentation.get(`type:${typeName}`); + const description = docs?.description || `Type defined in ${sourceFile.fileName}`; + + const initializer = declaration.initializer; + if (!initializer) return; - if (definition.includes('enum')) { - const enumMatch = fullMatch.match(/\[(.*?)\]/s); - const enumValues = enumMatch ? - enumMatch[1] - .split(',') - .map(v => v.trim().replace(/['"]/g, '')) - .filter(Boolean) - .sort() : []; - - types.push({ - name: typeName, - type: 'enum', + const typeText = sourceFile.text.slice(initializer.pos, initializer.end); + + if (typeText.includes('z.enum')) { + types.push(extractEnumType( + typeName, + typeText, description, - values: enumValues, - sourceFile: filename - }); - } else if (definition.includes('object')) { - const properties: Property[] = []; - const propsMatch = definition.match(/object\(\{([\s\S]*?)\}\)/s); - - if (propsMatch) { - const propsContent = propsMatch[1]; - const propLines = propsContent.split('\n'); - - const props = propLines - .map(line => { - const propMatch = line.match(/^\s*(\w+):\s*(.*?)(?:,\s*$|$)/); - if (propMatch) { - const [_, propName, propType] = propMatch; - if (propName && propType) { - return { - name: propName.trim(), - type: parseZodType(propType.trim()), - description: '' - }; - } - } - return null; - }) - .filter((prop): prop is Property => prop !== null) - .sort((a, b) => a.name.localeCompare(b.name)); - - properties.push(...props); - } - - types.push({ - name: typeName, - type: 'object', + sourceFile.fileName + )); + } else if (typeText.includes('z.object')) { + const objectType = extractObjectType( + typeName, + initializer, description, - properties, - sourceFile: filename - }); + docs?.params || {}, + sourceFile.fileName, + program.getTypeChecker() + ); + types.push(objectType); } - } + }); - return types; + return types.sort((a, b) => a.name.localeCompare(b.name)); } -export function getAllTypesByFiles(files: string[]): CustomType[] { - const sortedFiles = [...files].sort((a, b) => path.basename(a).localeCompare(path.basename(b))); - const typesMap = new Map(); +function extractEnumType( + name: string, + typeText: string, + description: string, + sourceFile: string +): TypeDocumentation { + const enumMatch = typeText.match(/\[(.*?)\]/s); + const values = enumMatch + ? enumMatch[1] + .split(',') + .map(v => v.trim().replace(/['"]/g, '')) + .filter(Boolean) + .sort() + : []; + + return { + name, + kind: 'enum', + description, + values, + sourceFile + }; +} + +function extractObjectType( + name: string, + node: ts.Expression, + description: string, + paramDocs: Record, + sourceFile: string, + typeChecker: ts.TypeChecker +): TypeDocumentation { + const properties: TypeProperty[] = []; - for (const file of sortedFiles) { - if (!file.endsWith('.ts')) continue; - - const content = fs.readFileSync(file, 'utf8'); - if (content.includes('z.object') || content.includes('z.enum')) { - const types = extractZodSchema(content, path.basename(file)); - typesMap.set(file, types); + if (ts.isCallExpression(node)) { + const objectArg = node.arguments[0]; + if (ts.isObjectLiteralExpression(objectArg)) { + objectArg.properties.forEach(prop => { + if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name)) { + const propName = prop.name.text; + const propType = parseZodType(prop.initializer.getText()); + + properties.push({ + name: propName, + type: propType, + description: paramDocs[propName] || '' + }); + } + }); } } - const allTypes: CustomType[] = []; - for (const file of sortedFiles) { - const types = typesMap.get(file); - if (types) { - allTypes.push(...types); - } - } - - return allTypes; + return { + name, + kind: 'object', + description, + properties: properties.sort((a, b) => a.name.localeCompare(b.name)), + sourceFile + }; } \ No newline at end of file diff --git a/docs/shared-utils.ts b/docs/shared-utils.ts new file mode 100644 index 0000000..17b6d3f --- /dev/null +++ b/docs/shared-utils.ts @@ -0,0 +1,263 @@ +import * as ts from 'typescript'; +import * as fs from 'fs'; +import * as path from 'path'; +import { TypeDocumentation, MethodDocumentation } from './types'; + +export interface FileProcessingOptions { + sourceDir: string; + excludePatterns?: RegExp[]; + includeExtensions?: string[]; +} + +export interface JSDocInfo { + description: string; + params: Record; + returns?: string; + example?: string; + tags: Record; +} + +/** + * Gets all files recursively from a directory matching specified criteria + */ +export function getAllFiles({ + sourceDir, + excludePatterns = [/node_modules/], + includeExtensions = ['.ts'] +}: FileProcessingOptions): string[] { + if (!fs.existsSync(sourceDir)) { + return []; + } + + const files = fs.readdirSync(sourceDir); + return files.flatMap(file => { + const fullPath = path.join(sourceDir, file); + + if (excludePatterns.some(pattern => pattern.test(fullPath))) { + return []; + } + + if (fs.statSync(fullPath).isDirectory()) { + return getAllFiles({ + sourceDir: fullPath, + excludePatterns, + includeExtensions + }); + } + + return includeExtensions.some(ext => file.endsWith(ext)) ? [fullPath] : []; + }); +} + +/** + * Creates a TypeScript program from source files + */ +export function createTSProgram(sourceFiles: string[]): ts.Program { + const options: ts.CompilerOptions = { + target: ts.ScriptTarget.ESNext, + module: ts.ModuleKind.ESNext, + allowJs: true, + checkJs: true, + noEmit: true, + types: ['node'], + skipLibCheck: true, + }; + + return ts.createProgram(sourceFiles, options); +} + +/** + * Cleans up documentation text + */ +function cleanDocText(text: string): string { + return text + .trim() + .replace(/^[-–—*]\s*/g, '') + .replace(/\s+/g, ' ') + .trim(); + } + +/** + * Gets a unique identifier for a node based on its type + */ +function getNodeIdentifier(node: ts.Node): string | null { + if (ts.isMethodDeclaration(node) && ts.isIdentifier(node.name)) { + return `method:${node.name.text}`; + } + if (ts.isTypeAliasDeclaration(node)) { + return `type:${node.name.text}`; + } + if (ts.isInterfaceDeclaration(node)) { + return `interface:${node.name.text}`; + } + if (ts.isClassDeclaration(node) && node.name) { + return `class:${node.name.text}`; + } + if (ts.isFunctionDeclaration(node) && node.name) { + return `function:${node.name.text}`; + } + if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name)) { + return `variable:${node.name.text}`; + } + return null; +} + +/** + * Extracts JSDoc documentation from a specific node + */ +function extractNodeDocs(node: ts.Node, sourceFile: ts.SourceFile): JSDocInfo { + const result: JSDocInfo = { + description: '', + params: {}, + tags: {} + }; + + const commentRanges = ts.getLeadingCommentRanges( + sourceFile.text, + node.getFullStart() + ); + + if (!commentRanges?.length) { + return result; + } + + const commentRange = commentRanges[commentRanges.length - 1]; + const commentLines = sourceFile.text + .slice(commentRange.pos, commentRange.end) + .replace(/\/\*\*|\*\/|\*/g, '') + .split('\n') + .map(line => line.trim()) + .filter(Boolean); + + let currentSection = 'description'; + let currentParam = ''; + + for (const line of commentLines) { + if (line.startsWith('@')) { + const [tag, ...content] = line.slice(1).split(' '); + const tagContent = content.join(' ').trim(); + + switch (tag) { + case 'param': + const paramMatch = tagContent.match(/^{[^}]+}\s+(\w+)\s*(.*)$/); + if (paramMatch) { + currentParam = paramMatch[1]; + result.params[currentParam] = cleanDocText(paramMatch[2]); // Czyszczenie już przy dodawaniu + } + currentSection = 'param'; + break; + + case 'returns': + case 'return': + result.returns = cleanDocText(tagContent); + currentSection = 'returns'; + break; + + case 'example': + result.example = cleanDocText(tagContent); + currentSection = 'example'; + break; + + default: + result.tags[tag] = cleanDocText(tagContent); + currentSection = tag; + } + } else { + switch (currentSection) { + case 'description': + result.description += (result.description ? ' ' : '') + cleanDocText(line); + break; + case 'param': + if (currentParam) { + const cleanedLine = cleanDocText(line); + result.params[currentParam] = result.params[currentParam] + ? result.params[currentParam] + ' ' + cleanedLine + : cleanedLine; + } + break; + case 'returns': + const cleanedReturnLine = cleanDocText(line); + result.returns = result.returns + ? result.returns + ' ' + cleanedReturnLine + : cleanedReturnLine; + break; + case 'example': + const cleanedExampleLine = cleanDocText(line); + result.example = result.example + ? result.example + ' ' + cleanedExampleLine + : cleanedExampleLine; + break; + default: + if (result.tags[currentSection]) { + const cleanedTagLine = cleanDocText(line); + result.tags[currentSection] += ' ' + cleanedTagLine; + } + } + } + } + return result; + } + +/** + * Extracts JSDoc documentation from TypeScript nodes in a file + */ +export function extractJSDoc( + filePath: string, + predicate: (node: ts.Node) => boolean = () => true +): Map { + const program = ts.createProgram([filePath], { + target: ts.ScriptTarget.ESNext, + module: ts.ModuleKind.ESNext, + }); + + const sourceFile = program.getSourceFile(filePath); + if (!sourceFile) { + console.warn(`Could not find source file: ${filePath}`); + return new Map(); + } + + const docs = new Map(); + + function visit(node: ts.Node) { + if (predicate(node)) { + const nodeIdentifier = getNodeIdentifier(node); + if (nodeIdentifier && sourceFile) { + const documentation = extractNodeDocs(node, sourceFile); + docs.set(nodeIdentifier, documentation); + } + } + ts.forEachChild(node, visit); + } + + visit(sourceFile); + return docs; +} + +/** + * Ensures output directory exists and writes documentation to JSON file + */ +export function writeDocs( + outputPath: string, + documentation: { methods: MethodDocumentation[]; types: TypeDocumentation[]; } +): void { + const outputDir = path.dirname(outputPath); + if (!fs.existsSync(outputDir)) { + fs.mkdirSync(outputDir, { recursive: true }); + } + + fs.writeFileSync( + outputPath, + JSON.stringify(documentation, null, 2) + ); +} + +/** + * Node visitor helper for TypeScript AST + */ +export function visitNodes( + node: ts.Node, + visitor: (node: ts.Node) => void +): void { + visitor(node); + ts.forEachChild(node, node => visitNodes(node, visitor)); +} \ No newline at end of file diff --git a/docs/types.ts b/docs/types.ts new file mode 100644 index 0000000..d70ef8e --- /dev/null +++ b/docs/types.ts @@ -0,0 +1,85 @@ +import * as ts from 'typescript'; + +/** + * Base interface for documented items + */ +export interface DocumentedItem { + name: string; + description: string; + sourceFile: string; +} + +/** + * Represents a method parameter + */ +export interface Parameter { + name: string; + type: string; + description: string; +} + +/** + * Documentation for an API method + */ +export interface MethodDocumentation extends DocumentedItem { + parameters: Parameter[]; + endpoint: string; + httpMethod: 'GET' | 'POST'; + returnType: string; + recursive: boolean; +} + +/** + * Represents a property in a type definition + */ +export interface TypeProperty extends Parameter {} + +/** + * Documentation for a type definition + */ +export interface TypeDocumentation extends DocumentedItem { + kind: 'enum' | 'object'; + properties?: TypeProperty[]; + values?: string[]; +} + +/** + * Complete API documentation + */ +export interface Documentation { + methods: MethodDocumentation[]; + types: TypeDocumentation[]; +} + +/** + * Represents parsed JSDoc comments + */ +export interface ParsedComment { + description: string; + params: Record; + returns?: string; + example?: string; +} + +/** + * Configuration for processing source files + */ +export interface FileProcessingConfig { + sourceDir: string; + excludePatterns?: RegExp[]; + includeExtensions?: string[]; +} + +/** + * Options for generating documentation + */ +export interface GenerateOptions { + outputDir: string; + sourceDir: string; + typeDescriptionsPath?: string; +} + +/** + * Node visitor function type + */ +export type NodeVisitor = (node: ts.Node) => void; \ No newline at end of file diff --git a/docs/utils/doc-parser.ts b/docs/utils/doc-parser.ts deleted file mode 100644 index 955286d..0000000 --- a/docs/utils/doc-parser.ts +++ /dev/null @@ -1,59 +0,0 @@ -import * as ts from 'typescript'; - -export interface ParsedDoc { - description: string; - params: Record; - returnType?: string; -} - -export function extractDocComment(node: ts.Node, sourceFile: ts.SourceFile): string { - const ranges = ts.getLeadingCommentRanges(sourceFile.text, node.pos); - if (!ranges || ranges.length === 0) return ''; - - const commentRange = ranges[ranges.length - 1]; - return sourceFile.text.substring(commentRange.pos, commentRange.end); -} - -export function parseDocComment(comment: string): ParsedDoc { - if (!comment) { - return { description: '', params: {} }; - } - - const result: ParsedDoc = { - description: '', - params: {}, - }; - - const lines = comment - .replace(/\/\*\*|\*\/|\*/g, '') - .split('\n') - .map(line => line.trim()) - .filter(Boolean); - - let currentSection = 'description'; - - for (const line of lines) { - if (line.startsWith('@param')) { - const paramMatch = line.match(/@param\s+(\w+)\s*-?\s*(.*)/); - if (paramMatch) { - const [, name, description] = paramMatch; - result.params[name] = description || ''; - } - continue; - } - - if (line.startsWith('@returns')) { - const returnMatch = line.match(/@returns\s+(.*)/); - if (returnMatch) { - result.returnType = returnMatch[1]; - } - continue; - } - - if (!line.startsWith('@') && currentSection === 'description') { - result.description += (result.description ? ' ' : '') + line; - } - } - - return result; -} \ No newline at end of file diff --git a/docs/utils/zod-type-parser.ts b/docs/utils/zod-type-parser.ts new file mode 100644 index 0000000..5041eb6 --- /dev/null +++ b/docs/utils/zod-type-parser.ts @@ -0,0 +1,59 @@ +/** + * Converts a Zod type string into its TypeScript equivalent + */ +export function parseZodType(zodType: string): string { + const typeMap = { + 'z.string()': 'string', + 'z.number()': 'number', + 'z.boolean()': 'boolean' + }; + + const type = zodType.trim(); + + if (type.endsWith('Schema')) { + return type.replace('Schema', ''); + } + + if (type.includes('.nullable()')) { + const baseType = type.replace('.nullable()', ''); + return `${parseZodType(baseType)} | null`; + } + + for (const [key, baseType] of Object.entries(typeMap)) { + if (type.startsWith(key)) { + return baseType; + } + } + + if (type.startsWith('z.array')) { + const innerMatch = type.match(/z\.array\((.*)\)/); + if (!innerMatch) return 'unknown[]'; + return `${parseZodType(innerMatch[1])}[]`; + } + + if (type.startsWith('z.record')) { + const matches = type.match(/z\.record\((.*?),\s*([\s\S]*?)\)(?![\s\S]*\)$)/); + if (!matches) return 'Record'; + const [_, keyType, valueType] = matches; + const parsedValueType = parseZodType(valueType.trim()); + const parsedKeyType = parseZodType(keyType.trim()); + + return `Record<${parsedKeyType}, ${parsedValueType}>`; + } + + if (type.startsWith('z.tuple')) { + const innerMatch = type.match(/z\.tuple\(\[(.*)\]\)/); + if (!innerMatch) return '[unknown]'; + const types = innerMatch[1].split(',').map(t => parseZodType(t.trim())); + return `[${types.join(', ')}]`; + } + + if (type.includes('z.enum')) { + return type.match(/\[(.*?)\]/)?.[1] + .split(',') + .map(v => v.trim().replace(/['"]/g, '')) + .join(' | ') || 'enum'; + } + + return type.replace('z.', ''); + } \ No newline at end of file From 1052b364c53e40885251297dde9ed07bb30c2d6f Mon Sep 17 00:00:00 2001 From: gmemez Date: Thu, 6 Feb 2025 18:01:15 +0700 Subject: [PATCH 3/6] amend --- docs/generateMethodsDocs.ts | 3 +- docs/generateTypesDocs.ts | 2 +- docs/shared-utils.ts | 175 --------------------------------- docs/utils/jsdoc-extractor.ts | 180 ++++++++++++++++++++++++++++++++++ 4 files changed, 183 insertions(+), 177 deletions(-) create mode 100644 docs/utils/jsdoc-extractor.ts diff --git a/docs/generateMethodsDocs.ts b/docs/generateMethodsDocs.ts index db0e580..f05088a 100644 --- a/docs/generateMethodsDocs.ts +++ b/docs/generateMethodsDocs.ts @@ -1,6 +1,7 @@ import * as ts from 'typescript'; import { MethodDocumentation } from './types'; -import { extractJSDoc, visitNodes } from './shared-utils'; +import { visitNodes } from './shared-utils'; +import { extractJSDoc } from './utils/jsdoc-extractor'; import api from '../src/api'; /** diff --git a/docs/generateTypesDocs.ts b/docs/generateTypesDocs.ts index abf1e44..99acccf 100644 --- a/docs/generateTypesDocs.ts +++ b/docs/generateTypesDocs.ts @@ -1,7 +1,7 @@ import * as ts from 'typescript'; import { TypeDocumentation, TypeProperty } from './types'; import { parseZodType } from './utils/zod-type-parser'; -import { extractJSDoc } from './shared-utils'; +import { extractJSDoc } from './utils/jsdoc-extractor'; export function generateTypeDocs( sourceFile: ts.SourceFile, diff --git a/docs/shared-utils.ts b/docs/shared-utils.ts index 17b6d3f..d5ecedb 100644 --- a/docs/shared-utils.ts +++ b/docs/shared-utils.ts @@ -9,14 +9,6 @@ export interface FileProcessingOptions { includeExtensions?: string[]; } -export interface JSDocInfo { - description: string; - params: Record; - returns?: string; - example?: string; - tags: Record; -} - /** * Gets all files recursively from a directory matching specified criteria */ @@ -66,173 +58,6 @@ export function createTSProgram(sourceFiles: string[]): ts.Program { return ts.createProgram(sourceFiles, options); } -/** - * Cleans up documentation text - */ -function cleanDocText(text: string): string { - return text - .trim() - .replace(/^[-–—*]\s*/g, '') - .replace(/\s+/g, ' ') - .trim(); - } - -/** - * Gets a unique identifier for a node based on its type - */ -function getNodeIdentifier(node: ts.Node): string | null { - if (ts.isMethodDeclaration(node) && ts.isIdentifier(node.name)) { - return `method:${node.name.text}`; - } - if (ts.isTypeAliasDeclaration(node)) { - return `type:${node.name.text}`; - } - if (ts.isInterfaceDeclaration(node)) { - return `interface:${node.name.text}`; - } - if (ts.isClassDeclaration(node) && node.name) { - return `class:${node.name.text}`; - } - if (ts.isFunctionDeclaration(node) && node.name) { - return `function:${node.name.text}`; - } - if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name)) { - return `variable:${node.name.text}`; - } - return null; -} - -/** - * Extracts JSDoc documentation from a specific node - */ -function extractNodeDocs(node: ts.Node, sourceFile: ts.SourceFile): JSDocInfo { - const result: JSDocInfo = { - description: '', - params: {}, - tags: {} - }; - - const commentRanges = ts.getLeadingCommentRanges( - sourceFile.text, - node.getFullStart() - ); - - if (!commentRanges?.length) { - return result; - } - - const commentRange = commentRanges[commentRanges.length - 1]; - const commentLines = sourceFile.text - .slice(commentRange.pos, commentRange.end) - .replace(/\/\*\*|\*\/|\*/g, '') - .split('\n') - .map(line => line.trim()) - .filter(Boolean); - - let currentSection = 'description'; - let currentParam = ''; - - for (const line of commentLines) { - if (line.startsWith('@')) { - const [tag, ...content] = line.slice(1).split(' '); - const tagContent = content.join(' ').trim(); - - switch (tag) { - case 'param': - const paramMatch = tagContent.match(/^{[^}]+}\s+(\w+)\s*(.*)$/); - if (paramMatch) { - currentParam = paramMatch[1]; - result.params[currentParam] = cleanDocText(paramMatch[2]); // Czyszczenie już przy dodawaniu - } - currentSection = 'param'; - break; - - case 'returns': - case 'return': - result.returns = cleanDocText(tagContent); - currentSection = 'returns'; - break; - - case 'example': - result.example = cleanDocText(tagContent); - currentSection = 'example'; - break; - - default: - result.tags[tag] = cleanDocText(tagContent); - currentSection = tag; - } - } else { - switch (currentSection) { - case 'description': - result.description += (result.description ? ' ' : '') + cleanDocText(line); - break; - case 'param': - if (currentParam) { - const cleanedLine = cleanDocText(line); - result.params[currentParam] = result.params[currentParam] - ? result.params[currentParam] + ' ' + cleanedLine - : cleanedLine; - } - break; - case 'returns': - const cleanedReturnLine = cleanDocText(line); - result.returns = result.returns - ? result.returns + ' ' + cleanedReturnLine - : cleanedReturnLine; - break; - case 'example': - const cleanedExampleLine = cleanDocText(line); - result.example = result.example - ? result.example + ' ' + cleanedExampleLine - : cleanedExampleLine; - break; - default: - if (result.tags[currentSection]) { - const cleanedTagLine = cleanDocText(line); - result.tags[currentSection] += ' ' + cleanedTagLine; - } - } - } - } - return result; - } - -/** - * Extracts JSDoc documentation from TypeScript nodes in a file - */ -export function extractJSDoc( - filePath: string, - predicate: (node: ts.Node) => boolean = () => true -): Map { - const program = ts.createProgram([filePath], { - target: ts.ScriptTarget.ESNext, - module: ts.ModuleKind.ESNext, - }); - - const sourceFile = program.getSourceFile(filePath); - if (!sourceFile) { - console.warn(`Could not find source file: ${filePath}`); - return new Map(); - } - - const docs = new Map(); - - function visit(node: ts.Node) { - if (predicate(node)) { - const nodeIdentifier = getNodeIdentifier(node); - if (nodeIdentifier && sourceFile) { - const documentation = extractNodeDocs(node, sourceFile); - docs.set(nodeIdentifier, documentation); - } - } - ts.forEachChild(node, visit); - } - - visit(sourceFile); - return docs; -} - /** * Ensures output directory exists and writes documentation to JSON file */ diff --git a/docs/utils/jsdoc-extractor.ts b/docs/utils/jsdoc-extractor.ts new file mode 100644 index 0000000..54f1390 --- /dev/null +++ b/docs/utils/jsdoc-extractor.ts @@ -0,0 +1,180 @@ +import * as ts from 'typescript'; + +export interface JSDocInfo { + description: string; + params: Record; + returns?: string; + example?: string; + tags: Record; +} + +/** + * Extracts JSDoc documentation from TypeScript nodes in a file + * @param filePath - Path to the TypeScript file + * @param predicate - Function to identify the nodes we want to extract docs from + * @returns Map of node identifiers to their documentation + */ +export function extractJSDoc( + filePath: string, + predicate: (node: ts.Node) => boolean = () => true +): Map { + const program = ts.createProgram([filePath], { + target: ts.ScriptTarget.ESNext, + module: ts.ModuleKind.ESNext, + }); + + const sourceFile = program.getSourceFile(filePath); + if (!sourceFile) { + console.warn(`Could not find source file: ${filePath}`); + return new Map(); + } + + const docs = new Map(); + + function visit(node: ts.Node) { + if (predicate(node)) { + const nodeIdentifier = getNodeIdentifier(node); + if (nodeIdentifier && sourceFile) { + const documentation = extractNodeDocs(node, sourceFile); + docs.set(nodeIdentifier, documentation); + } + } + ts.forEachChild(node, visit); + } + + visit(sourceFile); + return docs; +} + +/** + * Gets a unique identifier for a node based on its type + */ +function getNodeIdentifier(node: ts.Node): string | null { + if (ts.isMethodDeclaration(node) && ts.isIdentifier(node.name)) { + return `method:${node.name.text}`; + } + if (ts.isTypeAliasDeclaration(node)) { + return `type:${node.name.text}`; + } + if (ts.isInterfaceDeclaration(node)) { + return `interface:${node.name.text}`; + } + if (ts.isClassDeclaration(node) && node.name) { + return `class:${node.name.text}`; + } + if (ts.isFunctionDeclaration(node) && node.name) { + return `function:${node.name.text}`; + } + if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name)) { + return `variable:${node.name.text}`; + } + return null; +} + +/** + * Cleans up documentation text by removing initial dashes, stars and normalizing whitespace + */ +function cleanDocText(text: string): string { + return text + .trim() + .replace(/^[-–—*]\s*/g, '') + .replace(/\s+/g, ' ') + .trim(); +} + +/** + * Extracts JSDoc documentation from a specific node + */ +function extractNodeDocs(node: ts.Node, sourceFile: ts.SourceFile): JSDocInfo { + const result: JSDocInfo = { + description: '', + params: {}, + tags: {} + }; + + const commentRanges = ts.getLeadingCommentRanges( + sourceFile.text, + node.getFullStart() + ); + + if (!commentRanges?.length) { + return result; + } + + const commentRange = commentRanges[commentRanges.length - 1]; + const commentLines = sourceFile.text + .slice(commentRange.pos, commentRange.end) + .replace(/\/\*\*|\*\/|\*/g, '') + .split('\n') + .map(line => line.trim()) + .filter(Boolean); + + let currentSection = 'description'; + let currentParam = ''; + + for (const line of commentLines) { + if (line.startsWith('@')) { + const [tag, ...content] = line.slice(1).split(' '); + const tagContent = content.join(' ').trim(); + + switch (tag) { + case 'param': + const paramMatch = tagContent.match(/^{[^}]+}\s+(\w+)\s*(.*)$/); + if (paramMatch) { + currentParam = paramMatch[1]; + result.params[currentParam] = cleanDocText(paramMatch[2]); + } + currentSection = 'param'; + break; + + case 'returns': + case 'return': + result.returns = cleanDocText(tagContent); + currentSection = 'returns'; + break; + + case 'example': + result.example = cleanDocText(tagContent); + currentSection = 'example'; + break; + + default: + result.tags[tag] = cleanDocText(tagContent); + currentSection = tag; + } + } else { + switch (currentSection) { + case 'description': + result.description += (result.description ? ' ' : '') + cleanDocText(line); + break; + case 'param': + if (currentParam) { + const cleanedLine = cleanDocText(line); + result.params[currentParam] = result.params[currentParam] + ? result.params[currentParam] + ' ' + cleanedLine + : cleanedLine; + } + break; + case 'returns': + const cleanedReturnLine = cleanDocText(line); + result.returns = result.returns + ? result.returns + ' ' + cleanedReturnLine + : cleanedReturnLine; + break; + case 'example': + const cleanedExampleLine = cleanDocText(line); + result.example = result.example + ? result.example + ' ' + cleanedExampleLine + : cleanedExampleLine; + break; + default: + if (result.tags[currentSection]) { + const cleanedTagLine = cleanDocText(line); + result.tags[currentSection] += ' ' + cleanedTagLine; + } + } + } + } + + return result; +} \ No newline at end of file From 1d8924841104d10d499dfb5d8c28b2db925938e7 Mon Sep 17 00:00:00 2001 From: gmemez Date: Thu, 6 Feb 2025 18:56:48 +0700 Subject: [PATCH 4/6] amend --- docs/api-docs.json | 104 ++++++++++---------- docs/generate.ts | 52 +++++----- docs/generateMethodsDocs.ts | 2 +- docs/generateTypesDocs.ts | 2 +- docs/shared-utils.ts | 16 +++- docs/utils/jsdoc-extractor.ts | 172 +++++++++++++--------------------- 6 files changed, 152 insertions(+), 196 deletions(-) diff --git a/docs/api-docs.json b/docs/api-docs.json index de7b190..689e09b 100644 --- a/docs/api-docs.json +++ b/docs/api-docs.json @@ -14,7 +14,7 @@ "httpMethod": "GET", "returnType": "Promise", "recursive": false, - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" + "sourceFile": "src/client.ts" }, { "name": "getBlockCount", @@ -24,7 +24,7 @@ "httpMethod": "GET", "returnType": "Promise", "recursive": false, - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" + "sourceFile": "src/client.ts" }, { "name": "getBlockHash", @@ -34,7 +34,7 @@ "httpMethod": "GET", "returnType": "Promise", "recursive": false, - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" + "sourceFile": "src/client.ts" }, { "name": "getBlockHashByHeight", @@ -50,7 +50,7 @@ "httpMethod": "GET", "returnType": "Promise", "recursive": false, - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" + "sourceFile": "src/client.ts" }, { "name": "getBlockHashByHeightRecursive", @@ -66,7 +66,7 @@ "httpMethod": "GET", "returnType": "Promise", "recursive": true, - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" + "sourceFile": "src/client.ts" }, { "name": "getBlockHashRecursive", @@ -76,7 +76,7 @@ "httpMethod": "GET", "returnType": "Promise", "recursive": true, - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" + "sourceFile": "src/client.ts" }, { "name": "getBlockHeight", @@ -86,7 +86,7 @@ "httpMethod": "GET", "returnType": "Promise", "recursive": false, - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" + "sourceFile": "src/client.ts" }, { "name": "getBlockHeightRecursive", @@ -96,7 +96,7 @@ "httpMethod": "GET", "returnType": "Promise", "recursive": true, - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" + "sourceFile": "src/client.ts" }, { "name": "getBlockInfo", @@ -112,7 +112,7 @@ "httpMethod": "GET", "returnType": "Promise", "recursive": false, - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" + "sourceFile": "src/client.ts" }, { "name": "getBlockInfoRecursive", @@ -128,7 +128,7 @@ "httpMethod": "GET", "returnType": "Promise", "recursive": true, - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" + "sourceFile": "src/client.ts" }, { "name": "getBlocksLatest", @@ -138,7 +138,7 @@ "httpMethod": "GET", "returnType": "Promise", "recursive": false, - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" + "sourceFile": "src/client.ts" }, { "name": "getBlockTime", @@ -148,7 +148,7 @@ "httpMethod": "GET", "returnType": "Promise", "recursive": false, - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" + "sourceFile": "src/client.ts" }, { "name": "getBlockTimeRecursive", @@ -158,7 +158,7 @@ "httpMethod": "GET", "returnType": "Promise", "recursive": true, - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" + "sourceFile": "src/client.ts" }, { "name": "getChild", @@ -179,7 +179,7 @@ "httpMethod": "GET", "returnType": "Promise", "recursive": false, - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" + "sourceFile": "src/client.ts" }, { "name": "getChildren", @@ -195,7 +195,7 @@ "httpMethod": "GET", "returnType": "Promise", "recursive": true, - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" + "sourceFile": "src/client.ts" }, { "name": "getChildrenByPage", @@ -216,7 +216,7 @@ "httpMethod": "GET", "returnType": "Promise", "recursive": true, - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" + "sourceFile": "src/client.ts" }, { "name": "getChildrenInfo", @@ -232,7 +232,7 @@ "httpMethod": "GET", "returnType": "Promise", "recursive": true, - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" + "sourceFile": "src/client.ts" }, { "name": "getChildrenInfoByPage", @@ -253,7 +253,7 @@ "httpMethod": "GET", "returnType": "Promise", "recursive": true, - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" + "sourceFile": "src/client.ts" }, { "name": "getInscriptionInfo", @@ -269,7 +269,7 @@ "httpMethod": "GET", "returnType": "Promise", "recursive": false, - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" + "sourceFile": "src/client.ts" }, { "name": "getInscriptionOnSat", @@ -290,7 +290,7 @@ "httpMethod": "GET", "returnType": "Promise", "recursive": true, - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" + "sourceFile": "src/client.ts" }, { "name": "getInscriptionRecursive", @@ -306,7 +306,7 @@ "httpMethod": "GET", "returnType": "Promise", "recursive": true, - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" + "sourceFile": "src/client.ts" }, { "name": "getInscriptions", @@ -316,7 +316,7 @@ "httpMethod": "GET", "returnType": "Promise", "recursive": false, - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" + "sourceFile": "src/client.ts" }, { "name": "getInscriptionsByBlock", @@ -332,7 +332,7 @@ "httpMethod": "GET", "returnType": "Promise", "recursive": false, - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" + "sourceFile": "src/client.ts" }, { "name": "getInscriptionsByIds", @@ -348,7 +348,7 @@ "httpMethod": "POST", "returnType": "Promise", "recursive": false, - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" + "sourceFile": "src/client.ts" }, { "name": "getInscriptionsByPage", @@ -364,7 +364,7 @@ "httpMethod": "GET", "returnType": "Promise", "recursive": false, - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" + "sourceFile": "src/client.ts" }, { "name": "getInscriptionsOnSat", @@ -380,7 +380,7 @@ "httpMethod": "GET", "returnType": "Promise", "recursive": true, - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" + "sourceFile": "src/client.ts" }, { "name": "getInscriptionsOnSatByPage", @@ -401,7 +401,7 @@ "httpMethod": "GET", "returnType": "Promise", "recursive": true, - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" + "sourceFile": "src/client.ts" }, { "name": "getOutput", @@ -417,7 +417,7 @@ "httpMethod": "GET", "returnType": "Promise", "recursive": false, - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" + "sourceFile": "src/client.ts" }, { "name": "getOutputAssets", @@ -433,7 +433,7 @@ "httpMethod": "GET", "returnType": "Promise", "recursive": true, - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" + "sourceFile": "src/client.ts" }, { "name": "getOutputs", @@ -449,7 +449,7 @@ "httpMethod": "POST", "returnType": "Promise", "recursive": false, - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" + "sourceFile": "src/client.ts" }, { "name": "getOutputsByAddress", @@ -463,14 +463,14 @@ { "name": "type", "type": "OutputType", - "description": "" + "description": "Optional filter for specific output types" } ], "endpoint": "/outputs/{address}", "httpMethod": "GET", "returnType": "Promise", "recursive": false, - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" + "sourceFile": "src/client.ts" }, { "name": "getParents", @@ -486,7 +486,7 @@ "httpMethod": "GET", "returnType": "Promise", "recursive": true, - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" + "sourceFile": "src/client.ts" }, { "name": "getParentsByPage", @@ -507,7 +507,7 @@ "httpMethod": "GET", "returnType": "Promise", "recursive": true, - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" + "sourceFile": "src/client.ts" }, { "name": "getRune", @@ -523,7 +523,7 @@ "httpMethod": "GET", "returnType": "Promise", "recursive": false, - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" + "sourceFile": "src/client.ts" }, { "name": "getRunesByPage", @@ -539,7 +539,7 @@ "httpMethod": "GET", "returnType": "Promise", "recursive": false, - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" + "sourceFile": "src/client.ts" }, { "name": "getRunesLatest", @@ -549,7 +549,7 @@ "httpMethod": "GET", "returnType": "Promise", "recursive": false, - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" + "sourceFile": "src/client.ts" }, { "name": "getSat", @@ -565,7 +565,7 @@ "httpMethod": "GET", "returnType": "Promise", "recursive": false, - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" + "sourceFile": "src/client.ts" }, { "name": "getServerStatus", @@ -575,7 +575,7 @@ "httpMethod": "GET", "returnType": "Promise", "recursive": false, - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" + "sourceFile": "src/client.ts" }, { "name": "getTransaction", @@ -591,7 +591,7 @@ "httpMethod": "GET", "returnType": "Promise", "recursive": false, - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" + "sourceFile": "src/client.ts" }, { "name": "getTransactionHex", @@ -607,7 +607,7 @@ "httpMethod": "GET", "returnType": "Promise", "recursive": true, - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/client.ts" + "sourceFile": "src/client.ts" } ], "types": [ @@ -785,7 +785,7 @@ "description": "" } ], - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/schemas/block.ts" + "sourceFile": "src/schemas/block.ts" }, { "name": "BlockInfo", @@ -828,7 +828,7 @@ "description": "" } ], - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/schemas/block.ts" + "sourceFile": "src/schemas/block.ts" }, { "name": "BlocksResponse", @@ -851,7 +851,7 @@ "description": "" } ], - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/schemas/block.ts" + "sourceFile": "src/schemas/block.ts" }, { "name": "CharmType", @@ -1268,7 +1268,7 @@ "description": "" } ], - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/schemas/output.ts" + "sourceFile": "src/schemas/output.ts" }, { "name": "OutputInfo", @@ -1326,7 +1326,7 @@ "description": "" } ], - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/schemas/output.ts" + "sourceFile": "src/schemas/output.ts" }, { "name": "OutputType", @@ -1338,7 +1338,7 @@ "inscribed", "runic" ], - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/schemas/output.ts" + "sourceFile": "src/schemas/output.ts" }, { "name": "RarityType", @@ -1352,7 +1352,7 @@ "rare", "uncommon" ], - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/schemas/sat.ts" + "sourceFile": "src/schemas/sat.ts" }, { "name": "RuneBalance", @@ -1587,7 +1587,7 @@ "description": "" } ], - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/schemas/sat.ts" + "sourceFile": "src/schemas/sat.ts" }, { "name": "ServerStatus", @@ -1675,12 +1675,12 @@ "description": "" } ], - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/schemas/status.ts" + "sourceFile": "src/schemas/status.ts" }, { "name": "Time", "kind": "object", - "description": "Type defined in /Users/gole/Desktop/ord-js/ord-js/src/schemas/status.ts", + "description": "Type defined in src/schemas/status.ts", "properties": [ { "name": "nanos", @@ -1693,7 +1693,7 @@ "description": "" } ], - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/schemas/status.ts" + "sourceFile": "src/schemas/status.ts" }, { "name": "Transaction", diff --git a/docs/generate.ts b/docs/generate.ts index 6eb7857..f603bbe 100644 --- a/docs/generate.ts +++ b/docs/generate.ts @@ -12,14 +12,17 @@ function generateDocs(sourceFiles: string[]): Documentation { const program = createTSProgram(sourceFiles); const methods: MethodDocumentation[] = []; const typesByFile = new Map(); + // First pass: collect types for (const sourceFile of program.getSourceFiles()) { const fileName = sourceFile.fileName; - if (fileName.includes('node_modules')) { + // Skip node_modules and declaration files + if (fileName.includes('node_modules') || fileName.endsWith('.d.ts')) { continue; } + // Look for Zod schemas if (sourceFile.getText().includes('z.object') || sourceFile.getText().includes('z.enum')) { const types = generateTypeDocs(sourceFile, program); @@ -27,20 +30,15 @@ function generateDocs(sourceFiles: string[]): Documentation { typesByFile.set(fileName, types); } } - } - // Second pass: collect methods - for (const sourceFile of program.getSourceFiles()) { - const fileName = sourceFile.fileName; - - if (fileName.includes('node_modules')) { - continue; + // Also collect methods from this file + const fileMethods = generateMethodDocs(sourceFile, program); + if (fileMethods.length > 0) { + methods.push(...fileMethods); } - - methods.push(...generateMethodDocs(sourceFile, program)); } - // Combine all types preserving file order + // Combine all types const allTypes = Array.from(typesByFile.values()).flat(); return { @@ -54,28 +52,24 @@ const SOURCE_DIR = './src'; const DOCS_DIR = path.join(process.cwd(), 'docs'); // Get source files -const sourceFiles = [ - ...getAllFiles({ - sourceDir: SOURCE_DIR, - includeExtensions: ['.ts'] - }), - ...getAllFiles({ - sourceDir: path.join(SOURCE_DIR, 'schemas'), - includeExtensions: ['.ts'], - }), - ...getAllFiles({ - sourceDir: path.join(SOURCE_DIR, 'types'), - includeExtensions: ['.ts'], - }) -]; +const sourceFiles = getAllFiles({ + sourceDir: SOURCE_DIR, + includeExtensions: ['.ts'], + excludePatterns: [ + /\.test\.ts$/, + /\.spec\.ts$/, + /\.d\.ts$/, + /\/dist\//, + /\/build\//, + /\/node_modules\// + ] +}); -// Generate documentation +// Generate and write documentation const docs = generateDocs(sourceFiles); - -// Write the documentation to file writeDocs( path.join(DOCS_DIR, 'api-docs.json'), docs ); -console.log('Documentation generated successfully at docs/api-docs.json'); \ No newline at end of file +console.log(`Documentation generated from ${sourceFiles.length} files at docs/api-docs.json`); \ No newline at end of file diff --git a/docs/generateMethodsDocs.ts b/docs/generateMethodsDocs.ts index f05088a..2132bd1 100644 --- a/docs/generateMethodsDocs.ts +++ b/docs/generateMethodsDocs.ts @@ -16,7 +16,7 @@ export function generateMethodDocs( // Extract all method documentation from the file const methodDocumentation = extractJSDoc( - sourceFile.fileName, + sourceFile, node => ts.isMethodDeclaration(node) ); diff --git a/docs/generateTypesDocs.ts b/docs/generateTypesDocs.ts index 99acccf..015fb14 100644 --- a/docs/generateTypesDocs.ts +++ b/docs/generateTypesDocs.ts @@ -33,7 +33,7 @@ export function generateTypeDocs( // Get documentation from types/index.ts const typeDocumentation = typesFile ? extractJSDoc( - typesFile.fileName, + typesFile, node => ts.isTypeAliasDeclaration(node) && schemaNames.some(schema => node.name.text === schema.replace('Schema', '') diff --git a/docs/shared-utils.ts b/docs/shared-utils.ts index d5ecedb..fc41127 100644 --- a/docs/shared-utils.ts +++ b/docs/shared-utils.ts @@ -3,9 +3,11 @@ import * as fs from 'fs'; import * as path from 'path'; import { TypeDocumentation, MethodDocumentation } from './types'; +export type ExcludePattern = RegExp | ((path: string) => boolean); + export interface FileProcessingOptions { sourceDir: string; - excludePatterns?: RegExp[]; + excludePatterns?: ExcludePattern[]; includeExtensions?: string[]; } @@ -25,9 +27,15 @@ export function getAllFiles({ return files.flatMap(file => { const fullPath = path.join(sourceDir, file); - if (excludePatterns.some(pattern => pattern.test(fullPath))) { - return []; - } + const shouldExclude = excludePatterns.some(pattern => + pattern instanceof RegExp + ? pattern.test(fullPath) + : pattern(fullPath) + ); + + if (shouldExclude) { + return []; + } if (fs.statSync(fullPath).isDirectory()) { return getAllFiles({ diff --git a/docs/utils/jsdoc-extractor.ts b/docs/utils/jsdoc-extractor.ts index 54f1390..ba5e8f4 100644 --- a/docs/utils/jsdoc-extractor.ts +++ b/docs/utils/jsdoc-extractor.ts @@ -8,47 +8,30 @@ export interface JSDocInfo { tags: Record; } -/** - * Extracts JSDoc documentation from TypeScript nodes in a file - * @param filePath - Path to the TypeScript file - * @param predicate - Function to identify the nodes we want to extract docs from - * @returns Map of node identifiers to their documentation - */ export function extractJSDoc( - filePath: string, + sourceFile: ts.SourceFile, predicate: (node: ts.Node) => boolean = () => true ): Map { - const program = ts.createProgram([filePath], { - target: ts.ScriptTarget.ESNext, - module: ts.ModuleKind.ESNext, - }); - - const sourceFile = program.getSourceFile(filePath); - if (!sourceFile) { - console.warn(`Could not find source file: ${filePath}`); - return new Map(); - } - const docs = new Map(); - + function visit(node: ts.Node) { if (predicate(node)) { const nodeIdentifier = getNodeIdentifier(node); - if (nodeIdentifier && sourceFile) { + if (nodeIdentifier) { const documentation = extractNodeDocs(node, sourceFile); - docs.set(nodeIdentifier, documentation); + if (documentation.description || Object.keys(documentation.params).length > 0) { + docs.set(nodeIdentifier, documentation); + } } } ts.forEachChild(node, visit); } - + visit(sourceFile); + console.log(`Extracted ${docs.size} documentation entries from ${sourceFile.fileName}`); return docs; } -/** - * Gets a unique identifier for a node based on its type - */ function getNodeIdentifier(node: ts.Node): string | null { if (ts.isMethodDeclaration(node) && ts.isIdentifier(node.name)) { return `method:${node.name.text}`; @@ -71,9 +54,6 @@ function getNodeIdentifier(node: ts.Node): string | null { return null; } -/** - * Cleans up documentation text by removing initial dashes, stars and normalizing whitespace - */ function cleanDocText(text: string): string { return text .trim() @@ -82,9 +62,6 @@ function cleanDocText(text: string): string { .trim(); } -/** - * Extracts JSDoc documentation from a specific node - */ function extractNodeDocs(node: ts.Node, sourceFile: ts.SourceFile): JSDocInfo { const result: JSDocInfo = { description: '', @@ -92,89 +69,66 @@ function extractNodeDocs(node: ts.Node, sourceFile: ts.SourceFile): JSDocInfo { tags: {} }; - const commentRanges = ts.getLeadingCommentRanges( - sourceFile.text, - node.getFullStart() - ); - - if (!commentRanges?.length) { - return result; - } - - const commentRange = commentRanges[commentRanges.length - 1]; - const commentLines = sourceFile.text - .slice(commentRange.pos, commentRange.end) - .replace(/\/\*\*|\*\/|\*/g, '') - .split('\n') - .map(line => line.trim()) - .filter(Boolean); - - let currentSection = 'description'; - let currentParam = ''; - - for (const line of commentLines) { - if (line.startsWith('@')) { - const [tag, ...content] = line.slice(1).split(' '); - const tagContent = content.join(' ').trim(); + // Get JSDoc nodes + const jsDocs = ((node as any).jsDoc || []) as ts.JSDoc[]; + + for (const jsDoc of jsDocs) { + // Extract description from the main JSDoc comment + if (jsDoc.comment) { + const commentText = typeof jsDoc.comment === 'string' + ? jsDoc.comment + : Array.isArray(jsDoc.comment) + ? jsDoc.comment.map(part => part.text).join(' ') + : ''; + + result.description += (result.description ? ' ' : '') + cleanDocText(commentText); + } - switch (tag) { - case 'param': - const paramMatch = tagContent.match(/^{[^}]+}\s+(\w+)\s*(.*)$/); - if (paramMatch) { - currentParam = paramMatch[1]; - result.params[currentParam] = cleanDocText(paramMatch[2]); - } - currentSection = 'param'; - break; - - case 'returns': - case 'return': - result.returns = cleanDocText(tagContent); - currentSection = 'returns'; - break; - - case 'example': - result.example = cleanDocText(tagContent); - currentSection = 'example'; - break; - - default: - result.tags[tag] = cleanDocText(tagContent); - currentSection = tag; - } - } else { - switch (currentSection) { - case 'description': - result.description += (result.description ? ' ' : '') + cleanDocText(line); - break; - case 'param': - if (currentParam) { - const cleanedLine = cleanDocText(line); - result.params[currentParam] = result.params[currentParam] - ? result.params[currentParam] + ' ' + cleanedLine - : cleanedLine; - } - break; - case 'returns': - const cleanedReturnLine = cleanDocText(line); - result.returns = result.returns - ? result.returns + ' ' + cleanedReturnLine - : cleanedReturnLine; - break; - case 'example': - const cleanedExampleLine = cleanDocText(line); - result.example = result.example - ? result.example + ' ' + cleanedExampleLine - : cleanedExampleLine; - break; - default: - if (result.tags[currentSection]) { - const cleanedTagLine = cleanDocText(line); - result.tags[currentSection] += ' ' + cleanedTagLine; + // Process JSDoc tags + if (jsDoc.tags) { + for (const tag of jsDoc.tags) { + if (ts.isJSDocParameterTag(tag) && tag.name) { + const paramName = tag.name.getText(); + const comment = tag.comment + ? (typeof tag.comment === 'string' ? tag.comment : tag.comment.map(part => part.text).join(' ')) + : ''; + result.params[paramName] = cleanDocText(comment); + } + else if (ts.isJSDocReturnTag(tag)) { + const comment = tag.comment + ? (typeof tag.comment === 'string' ? tag.comment : tag.comment.map(part => part.text).join(' ')) + : ''; + result.returns = cleanDocText(comment); + } + else if (ts.isJSDoc(tag)) { + const tagName = (tag as any).tagName?.escapedText; + if (tagName) { + const comment = tag.comment + ? (typeof tag.comment === 'string' ? tag.comment : tag.comment.map(part => part.text).join(' ')) + : ''; + result.tags[tagName] = cleanDocText(comment); } + } } } } + // Fallback to looking for leading comments if no JSDoc is found + if (!result.description) { + const commentRanges = ts.getLeadingCommentRanges( + sourceFile.text, + node.getFullStart() + ); + + if (commentRanges?.length) { + const commentRange = commentRanges[commentRanges.length - 1]; + result.description = cleanDocText( + sourceFile.text + .slice(commentRange.pos, commentRange.end) + .replace(/\/\*\*|\*\/|\*/g, '') + ); + } + } + return result; } \ No newline at end of file From c2e6ca65b59481e4ee660d8e9b8184155c672d95 Mon Sep 17 00:00:00 2001 From: raphjaph Date: Thu, 6 Feb 2025 14:15:58 +0100 Subject: [PATCH 5/6] Amend --- .gitignore | 5 + docs/api-docs.json | 1760 -------------------------------------------- 2 files changed, 5 insertions(+), 1760 deletions(-) delete mode 100644 docs/api-docs.json diff --git a/.gitignore b/.gitignore index 9b1ee42..f96571c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,8 @@ +docs/api-docs.json + + + + # Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore # Logs diff --git a/docs/api-docs.json b/docs/api-docs.json deleted file mode 100644 index 689e09b..0000000 --- a/docs/api-docs.json +++ /dev/null @@ -1,1760 +0,0 @@ -{ - "methods": [ - { - "name": "getAddressInfo", - "description": "Retrieves information about a specific address including its outputs, inscriptions, and rune balances.", - "parameters": [ - { - "name": "address", - "type": "string", - "description": "Bitcoin address to query." - } - ], - "endpoint": "/address/{address}", - "httpMethod": "GET", - "returnType": "Promise", - "recursive": false, - "sourceFile": "src/client.ts" - }, - { - "name": "getBlockCount", - "description": "Retrieves the total number of blocks in the blockchain.", - "parameters": [], - "endpoint": "/blockcount", - "httpMethod": "GET", - "returnType": "Promise", - "recursive": false, - "sourceFile": "src/client.ts" - }, - { - "name": "getBlockHash", - "description": "Gets the hash of the latest block.", - "parameters": [], - "endpoint": "/blockhash", - "httpMethod": "GET", - "returnType": "Promise", - "recursive": false, - "sourceFile": "src/client.ts" - }, - { - "name": "getBlockHashByHeight", - "description": "Gets the hash of a block at the specified height.", - "parameters": [ - { - "name": "height", - "type": "number", - "description": "Block height to get hash for" - } - ], - "endpoint": "/blockhash/{height}", - "httpMethod": "GET", - "returnType": "Promise", - "recursive": false, - "sourceFile": "src/client.ts" - }, - { - "name": "getBlockHashByHeightRecursive", - "description": "Gets the block hash using the recursive endpoint.", - "parameters": [ - { - "name": "height", - "type": "number", - "description": "Block height" - } - ], - "endpoint": "/r/blockhash/{height}", - "httpMethod": "GET", - "returnType": "Promise", - "recursive": true, - "sourceFile": "src/client.ts" - }, - { - "name": "getBlockHashRecursive", - "description": "Gets the latest block hash using the recursive endpoint.", - "parameters": [], - "endpoint": "/r/blockhash", - "httpMethod": "GET", - "returnType": "Promise", - "recursive": true, - "sourceFile": "src/client.ts" - }, - { - "name": "getBlockHeight", - "description": "Gets the height of the latest block.", - "parameters": [], - "endpoint": "/blockheight", - "httpMethod": "GET", - "returnType": "Promise", - "recursive": false, - "sourceFile": "src/client.ts" - }, - { - "name": "getBlockHeightRecursive", - "description": "Gets the latest block height using the recursive endpoint.", - "parameters": [], - "endpoint": "/r/blockheight", - "httpMethod": "GET", - "returnType": "Promise", - "recursive": true, - "sourceFile": "src/client.ts" - }, - { - "name": "getBlockInfo", - "description": "Fetches details about a specific block by its height or hash.", - "parameters": [ - { - "name": "heightOrHash", - "type": "any", - "description": "Block height (number) or block hash (string)." - } - ], - "endpoint": "/block/{heightOrHash}", - "httpMethod": "GET", - "returnType": "Promise", - "recursive": false, - "sourceFile": "src/client.ts" - }, - { - "name": "getBlockInfoRecursive", - "description": "Gets detailed block information using the recursive endpoint.", - "parameters": [ - { - "name": "heightOrHash", - "type": "string | number", - "description": "Block height or hash" - } - ], - "endpoint": "/r/blockinfo/{heightOrHash}", - "httpMethod": "GET", - "returnType": "Promise", - "recursive": true, - "sourceFile": "src/client.ts" - }, - { - "name": "getBlocksLatest", - "description": "Returns the height of the latest block, the blockhashes of the last 100 blocks, and featured inscriptions from them.", - "parameters": [], - "endpoint": "/blocks", - "httpMethod": "GET", - "returnType": "Promise", - "recursive": false, - "sourceFile": "src/client.ts" - }, - { - "name": "getBlockTime", - "description": "Gets the timestamp of the latest block.", - "parameters": [], - "endpoint": "/blocktime", - "httpMethod": "GET", - "returnType": "Promise", - "recursive": false, - "sourceFile": "src/client.ts" - }, - { - "name": "getBlockTimeRecursive", - "description": "Gets block time using the recursive endpoint.", - "parameters": [], - "endpoint": "/r/blocktime", - "httpMethod": "GET", - "returnType": "Promise", - "recursive": true, - "sourceFile": "src/client.ts" - }, - { - "name": "getChild", - "description": "Gets a specific child inscription of a parent inscription.", - "parameters": [ - { - "name": "id", - "type": "string", - "description": "Parent inscription ID" - }, - { - "name": "child", - "type": "number", - "description": "Index of the child inscription" - } - ], - "endpoint": "/inscription/{id}/{child}", - "httpMethod": "GET", - "returnType": "Promise", - "recursive": false, - "sourceFile": "src/client.ts" - }, - { - "name": "getChildren", - "description": "Gets first 100 child inscriptions IDs.", - "parameters": [ - { - "name": "id", - "type": "string", - "description": "Parent inscription ID" - } - ], - "endpoint": "/r/children/{id}", - "httpMethod": "GET", - "returnType": "Promise", - "recursive": true, - "sourceFile": "src/client.ts" - }, - { - "name": "getChildrenByPage", - "description": "Gets paginated child inscription IDs.", - "parameters": [ - { - "name": "id", - "type": "string", - "description": "Parent inscription ID" - }, - { - "name": "page", - "type": "number", - "description": "Page number" - } - ], - "endpoint": "/r/children/{id}/{page}", - "httpMethod": "GET", - "returnType": "Promise", - "recursive": true, - "sourceFile": "src/client.ts" - }, - { - "name": "getChildrenInfo", - "description": "Gets details of the first 100 child inscriptions.", - "parameters": [ - { - "name": "id", - "type": "string", - "description": "Parent inscription ID" - } - ], - "endpoint": "/r/children/{id}/inscriptions", - "httpMethod": "GET", - "returnType": "Promise", - "recursive": true, - "sourceFile": "src/client.ts" - }, - { - "name": "getChildrenInfoByPage", - "description": "Gets paginated detailed child inscription information.", - "parameters": [ - { - "name": "id", - "type": "string", - "description": "Parent inscription ID" - }, - { - "name": "page", - "type": "number", - "description": "Page number" - } - ], - "endpoint": "/r/children/{id}/inscriptions/{page}", - "httpMethod": "GET", - "returnType": "Promise", - "recursive": true, - "sourceFile": "src/client.ts" - }, - { - "name": "getInscriptionInfo", - "description": "Retrieves information about a specific inscription by its ID.", - "parameters": [ - { - "name": "id", - "type": "string", - "description": "Inscription ID" - } - ], - "endpoint": "/inscription/{id}", - "httpMethod": "GET", - "returnType": "Promise", - "recursive": false, - "sourceFile": "src/client.ts" - }, - { - "name": "getInscriptionOnSat", - "description": "Gets ID of a specific inscription at an index by sat number. The inscription id at index of all inscriptions on a sat. Index may be a negative number to index from the back. 0 being the first and -1 being the most recent for example. Requires index with --index-sats flag.", - "parameters": [ - { - "name": "number", - "type": "number", - "description": "Satoshi number" - }, - { - "name": "index", - "type": "number", - "description": "Inscription index" - } - ], - "endpoint": "/r/sat/{number}/at/{index}", - "httpMethod": "GET", - "returnType": "Promise", - "recursive": true, - "sourceFile": "src/client.ts" - }, - { - "name": "getInscriptionRecursive", - "description": "Gets recursive inscription information.", - "parameters": [ - { - "name": "id", - "type": "string", - "description": "Inscription ID" - } - ], - "endpoint": "/r/inscription/{id}", - "httpMethod": "GET", - "returnType": "Promise", - "recursive": true, - "sourceFile": "src/client.ts" - }, - { - "name": "getInscriptions", - "description": "Gets a list of the 100 most recent inscriptions.", - "parameters": [], - "endpoint": "/inscriptions", - "httpMethod": "GET", - "returnType": "Promise", - "recursive": false, - "sourceFile": "src/client.ts" - }, - { - "name": "getInscriptionsByBlock", - "description": "Gets all inscriptions in a specific block.", - "parameters": [ - { - "name": "height", - "type": "number", - "description": "Block height to fetch inscriptions from" - } - ], - "endpoint": "/inscriptions/block/{height}", - "httpMethod": "GET", - "returnType": "Promise", - "recursive": false, - "sourceFile": "src/client.ts" - }, - { - "name": "getInscriptionsByIds", - "description": "Retrieves information about multiple inscriptions by their IDs.", - "parameters": [ - { - "name": "ids", - "type": "string[]", - "description": "Array of inscription IDs to fetch" - } - ], - "endpoint": "/inscriptions", - "httpMethod": "POST", - "returnType": "Promise", - "recursive": false, - "sourceFile": "src/client.ts" - }, - { - "name": "getInscriptionsByPage", - "description": "Gets inscriptions for a specific page number in paginated results.", - "parameters": [ - { - "name": "page", - "type": "number", - "description": "Page number to fetch" - } - ], - "endpoint": "/inscriptions/{page}", - "httpMethod": "GET", - "returnType": "Promise", - "recursive": false, - "sourceFile": "src/client.ts" - }, - { - "name": "getInscriptionsOnSat", - "description": "Gets the first 100 inscription ids on a sat. Requires index with --index-sats flag.", - "parameters": [ - { - "name": "number", - "type": "number", - "description": "Satoshi number" - } - ], - "endpoint": "/r/sat/{number}", - "httpMethod": "GET", - "returnType": "Promise", - "recursive": true, - "sourceFile": "src/client.ts" - }, - { - "name": "getInscriptionsOnSatByPage", - "description": "Gets paginated inscription ids for a specific satoshi.", - "parameters": [ - { - "name": "number", - "type": "number", - "description": "Satoshi number" - }, - { - "name": "page", - "type": "number", - "description": "Page number" - } - ], - "endpoint": "/r/sat/{number}/{page}", - "httpMethod": "GET", - "returnType": "Promise", - "recursive": true, - "sourceFile": "src/client.ts" - }, - { - "name": "getOutput", - "description": "Retrieves information about a specific UTXO.", - "parameters": [ - { - "name": "outpoint", - "type": "string", - "description": "Transaction outpoint in format {txid}:{vout}" - } - ], - "endpoint": "/output/{outpoint}", - "httpMethod": "GET", - "returnType": "Promise", - "recursive": false, - "sourceFile": "src/client.ts" - }, - { - "name": "getOutputAssets", - "description": "Gets assets held by an UTXO.", - "parameters": [ - { - "name": "outpoint", - "type": "string", - "description": "Transaction outpoint" - } - ], - "endpoint": "/r/utxo/{outpoint}", - "httpMethod": "GET", - "returnType": "Promise", - "recursive": true, - "sourceFile": "src/client.ts" - }, - { - "name": "getOutputs", - "description": "Gets information about multiple UTXOs.", - "parameters": [ - { - "name": "outpoints", - "type": "string[]", - "description": "Array of outpoints to fetch" - } - ], - "endpoint": "/outputs", - "httpMethod": "POST", - "returnType": "Promise", - "recursive": false, - "sourceFile": "src/client.ts" - }, - { - "name": "getOutputsByAddress", - "description": "Gets all UTXOs for a specific address, optionally filtered by type.", - "parameters": [ - { - "name": "address", - "type": "string", - "description": "Bitcoin address to get outputs for" - }, - { - "name": "type", - "type": "OutputType", - "description": "Optional filter for specific output types" - } - ], - "endpoint": "/outputs/{address}", - "httpMethod": "GET", - "returnType": "Promise", - "recursive": false, - "sourceFile": "src/client.ts" - }, - { - "name": "getParents", - "description": "Gets parent inscription IDs.", - "parameters": [ - { - "name": "id", - "type": "string", - "description": "Child inscription ID" - } - ], - "endpoint": "/r/parents/{id}", - "httpMethod": "GET", - "returnType": "Promise", - "recursive": true, - "sourceFile": "src/client.ts" - }, - { - "name": "getParentsByPage", - "description": "Gets paginated parent inscription IDs.", - "parameters": [ - { - "name": "id", - "type": "string", - "description": "Child inscription ID" - }, - { - "name": "page", - "type": "number", - "description": "Page number" - } - ], - "endpoint": "/r/parents/{id}/{page}", - "httpMethod": "GET", - "returnType": "Promise", - "recursive": true, - "sourceFile": "src/client.ts" - }, - { - "name": "getRune", - "description": "Gets information about a specific rune by name.", - "parameters": [ - { - "name": "name", - "type": "string", - "description": "Rune name" - } - ], - "endpoint": "/rune/{name}", - "httpMethod": "GET", - "returnType": "Promise", - "recursive": false, - "sourceFile": "src/client.ts" - }, - { - "name": "getRunesByPage", - "description": "Gets runes for a specific page number in paginated results.", - "parameters": [ - { - "name": "page", - "type": "number", - "description": "Page number to fetch" - } - ], - "endpoint": "/runes/{page}", - "httpMethod": "GET", - "returnType": "Promise", - "recursive": false, - "sourceFile": "src/client.ts" - }, - { - "name": "getRunesLatest", - "description": "Gets a list of the 100 most recent runes.", - "parameters": [], - "endpoint": "/runes", - "httpMethod": "GET", - "returnType": "Promise", - "recursive": false, - "sourceFile": "src/client.ts" - }, - { - "name": "getSat", - "description": "Gets information about a specific satoshi by its number.", - "parameters": [ - { - "name": "number", - "type": "number", - "description": "Satoshi number" - } - ], - "endpoint": "/sat/{number}", - "httpMethod": "GET", - "returnType": "Promise", - "recursive": false, - "sourceFile": "src/client.ts" - }, - { - "name": "getServerStatus", - "description": "Gets the current server status and information.", - "parameters": [], - "endpoint": "/status", - "httpMethod": "GET", - "returnType": "Promise", - "recursive": false, - "sourceFile": "src/client.ts" - }, - { - "name": "getTransaction", - "description": "Gets information about a specific transaction.", - "parameters": [ - { - "name": "txId", - "type": "string", - "description": "Transaction ID" - } - ], - "endpoint": "/tx/{txId}", - "httpMethod": "GET", - "returnType": "Promise", - "recursive": false, - "sourceFile": "src/client.ts" - }, - { - "name": "getTransactionHex", - "description": "Gets hex transaction data.", - "parameters": [ - { - "name": "txid", - "type": "string", - "description": "Transaction ID" - } - ], - "endpoint": "/r/tx/{txid}", - "httpMethod": "GET", - "returnType": "Promise", - "recursive": true, - "sourceFile": "src/client.ts" - } - ], - "types": [ - { - "name": "AddressInfo", - "kind": "object", - "description": "Comprehensive information about a Bitcoin address including its balance, outputs, inscriptions, and runes balances.", - "properties": [ - { - "name": "inscriptions", - "type": "string[] | null", - "description": "" - }, - { - "name": "outputs", - "type": "string[]", - "description": "" - }, - { - "name": "runes_balances", - "type": "string[][] | null", - "description": "" - }, - { - "name": "sat_balance", - "type": "number", - "description": "" - } - ], - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/schemas/address.ts" - }, - { - "name": "BlockDetails", - "kind": "object", - "description": "Detailed information about given block.", - "properties": [ - { - "name": "average_fee", - "type": "number", - "description": "" - }, - { - "name": "average_fee_rate", - "type": "number", - "description": "" - }, - { - "name": "bits", - "type": "number", - "description": "" - }, - { - "name": "chainwork", - "type": "string", - "description": "" - }, - { - "name": "confirmations", - "type": "number", - "description": "" - }, - { - "name": "difficulty", - "type": "number", - "description": "" - }, - { - "name": "feerate_percentiles", - "type": "number[]", - "description": "" - }, - { - "name": "hash", - "type": "BlockHash", - "description": "" - }, - { - "name": "height", - "type": "number", - "description": "" - }, - { - "name": "max_fee", - "type": "number", - "description": "" - }, - { - "name": "max_fee_rate", - "type": "number", - "description": "" - }, - { - "name": "max_tx_size", - "type": "number", - "description": "" - }, - { - "name": "median_fee", - "type": "number", - "description": "" - }, - { - "name": "median_time", - "type": "number | null", - "description": "" - }, - { - "name": "merkle_root", - "type": "string", - "description": "" - }, - { - "name": "min_fee", - "type": "number", - "description": "" - }, - { - "name": "min_fee_rate", - "type": "number", - "description": "" - }, - { - "name": "next_block", - "type": "BlockHash | null", - "description": "" - }, - { - "name": "nonce", - "type": "number", - "description": "" - }, - { - "name": "previous_block", - "type": "BlockHash | null", - "description": "" - }, - { - "name": "subsidy", - "type": "number", - "description": "" - }, - { - "name": "target", - "type": "string", - "description": "" - }, - { - "name": "timestamp", - "type": "number", - "description": "" - }, - { - "name": "total_fee", - "type": "number", - "description": "" - }, - { - "name": "total_size", - "type": "number", - "description": "" - }, - { - "name": "total_weight", - "type": "number", - "description": "" - }, - { - "name": "transaction_count", - "type": "number", - "description": "" - }, - { - "name": "version", - "type": "number", - "description": "" - } - ], - "sourceFile": "src/schemas/block.ts" - }, - { - "name": "BlockInfo", - "kind": "object", - "description": "Basic block information including inscriptions and runes.", - "properties": [ - { - "name": "best_height", - "type": "number", - "description": "" - }, - { - "name": "hash", - "type": "BlockHash", - "description": "" - }, - { - "name": "height", - "type": "number", - "description": "" - }, - { - "name": "inscriptions", - "type": "string[]", - "description": "" - }, - { - "name": "runes", - "type": "string[]", - "description": "" - }, - { - "name": "target", - "type": "string", - "description": "" - }, - { - "name": "transactions", - "type": "Transaction[]", - "description": "" - } - ], - "sourceFile": "src/schemas/block.ts" - }, - { - "name": "BlocksResponse", - "kind": "object", - "description": "Paginated response containing a list of recent blocks and metadata.", - "properties": [ - { - "name": "blocks", - "type": "BlockHash[]", - "description": "" - }, - { - "name": "featured_blocks", - "type": "Record", - "description": "" - }, - { - "name": "last", - "type": "number", - "description": "" - } - ], - "sourceFile": "src/schemas/block.ts" - }, - { - "name": "CharmType", - "kind": "enum", - "description": "Special characteristics or properties of a sat (e.g. \"cursed\", \"epic\", \"burned\").", - "values": [ - "burned", - "coin", - "cursed", - "epic", - "legendary", - "lost", - "mythic", - "nineball", - "palindrome", - "rare", - "reinscription", - "unbound", - "uncommon", - "vindicated" - ], - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/schemas/inscription.ts" - }, - { - "name": "ChildInfo", - "kind": "object", - "description": "Child inscription info retrieved from recursive endpoint.", - "properties": [ - { - "name": "charms", - "type": "CharmType[]", - "description": "" - }, - { - "name": "fee", - "type": "number", - "description": "" - }, - { - "name": "height", - "type": "number", - "description": "" - }, - { - "name": "id", - "type": "string", - "description": "" - }, - { - "name": "number", - "type": "number", - "description": "" - }, - { - "name": "output", - "type": "string", - "description": "" - }, - { - "name": "sat", - "type": "number", - "description": "" - }, - { - "name": "satpoint", - "type": "string", - "description": "" - }, - { - "name": "timestamp", - "type": "number", - "description": "" - } - ], - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/schemas/inscription.ts" - }, - { - "name": "ChildrenInfoResponse", - "kind": "object", - "description": "Paginated response containing child inscriptions detailed info.", - "properties": [ - { - "name": "children", - "type": "ChildInfo[]", - "description": "" - }, - { - "name": "more", - "type": "boolean", - "description": "" - }, - { - "name": "page", - "type": "number", - "description": "" - } - ], - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/schemas/inscription.ts" - }, - { - "name": "Input", - "kind": "object", - "description": "Transaction input containing previous output reference and witness data.", - "properties": [ - { - "name": "previous_output", - "type": "string", - "description": "" - }, - { - "name": "script_sig", - "type": "string", - "description": "" - }, - { - "name": "sequence", - "type": "number", - "description": "" - }, - { - "name": "witness", - "type": "string[]", - "description": "" - } - ], - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/schemas/transaction.ts" - }, - { - "name": "InscriptionID", - "kind": "object", - "description": "Response containing a single inscription ID.", - "properties": [ - { - "name": "id", - "type": "string | null", - "description": "" - } - ], - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/schemas/inscription.ts" - }, - { - "name": "InscriptionInfo", - "kind": "object", - "description": "Comprehensive information about an inscription including its content type, genesis data, location and transfer history.", - "properties": [ - { - "name": "address", - "type": "string | null", - "description": "" - }, - { - "name": "charms", - "type": "CharmType[]", - "description": "" - }, - { - "name": "child_count", - "type": "number", - "description": "" - }, - { - "name": "children", - "type": "string[]", - "description": "" - }, - { - "name": "content_length", - "type": "number | null", - "description": "" - }, - { - "name": "content_type", - "type": "string | null", - "description": "" - }, - { - "name": "effective_content_type", - "type": "string | null", - "description": "" - }, - { - "name": "fee", - "type": "number", - "description": "" - }, - { - "name": "height", - "type": "number", - "description": "" - }, - { - "name": "id", - "type": "string", - "description": "" - }, - { - "name": "metaprotocol", - "type": "string | null", - "description": "" - }, - { - "name": "next", - "type": "string | null", - "description": "" - }, - { - "name": "number", - "type": "number", - "description": "" - }, - { - "name": "parents", - "type": "string[]", - "description": "" - }, - { - "name": "previous", - "type": "string | null", - "description": "" - }, - { - "name": "rune", - "type": "string | null", - "description": "" - }, - { - "name": "sat", - "type": "number | null", - "description": "" - }, - { - "name": "satpoint", - "type": "string", - "description": "" - }, - { - "name": "timestamp", - "type": "number", - "description": "" - }, - { - "name": "value", - "type": "number | null", - "description": "" - } - ], - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/schemas/inscription.ts" - }, - { - "name": "InscriptionRecursive", - "kind": "object", - "description": "Comprehensive information about an inscription retrieved from recursive endpoint.", - "properties": [ - { - "name": "address", - "type": "string | null", - "description": "" - }, - { - "name": "charms", - "type": "CharmType[]", - "description": "" - }, - { - "name": "content_length", - "type": "number | null", - "description": "" - }, - { - "name": "content_type", - "type": "string | null", - "description": "" - }, - { - "name": "delegate", - "type": "string | null", - "description": "" - }, - { - "name": "fee", - "type": "number", - "description": "" - }, - { - "name": "height", - "type": "number", - "description": "" - }, - { - "name": "id", - "type": "string", - "description": "" - }, - { - "name": "number", - "type": "number", - "description": "" - }, - { - "name": "output", - "type": "string", - "description": "" - }, - { - "name": "sat", - "type": "number | null", - "description": "" - }, - { - "name": "satpoint", - "type": "string", - "description": "" - }, - { - "name": "timestamp", - "type": "number", - "description": "" - }, - { - "name": "value", - "type": "number | null", - "description": "" - } - ], - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/schemas/inscription.ts" - }, - { - "name": "InscriptionsIDsResponse", - "kind": "object", - "description": "Paginated response containing a list of inscription IDs", - "properties": [ - { - "name": "ids", - "type": "string[]", - "description": "" - }, - { - "name": "more", - "type": "boolean", - "description": "" - }, - { - "name": "page", - "type": "number", - "description": "" - } - ], - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/schemas/inscription.ts" - }, - { - "name": "InscriptionsResponse", - "kind": "object", - "description": "Paginated response containing a list of inscriptions IDs.", - "properties": [ - { - "name": "ids", - "type": "string[]", - "description": "" - }, - { - "name": "more", - "type": "boolean", - "description": "" - }, - { - "name": "page_index", - "type": "number", - "description": "" - } - ], - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/schemas/inscription.ts" - }, - { - "name": "Output", - "kind": "object", - "description": "Transaction output containing value and script pubkey.", - "properties": [ - { - "name": "script_pubkey", - "type": "string", - "description": "" - }, - { - "name": "value", - "type": "number", - "description": "" - } - ], - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/schemas/transaction.ts" - }, - { - "name": "OutputAssets", - "kind": "object", - "description": "Information about assets held by an UTXO.", - "properties": [ - { - "name": "inscriptions", - "type": "string[] | null", - "description": "" - }, - { - "name": "runes", - "type": "Record | null", - "description": "" - }, - { - "name": "sat_ranges", - "type": "SatRange[] | null", - "description": "" - }, - { - "name": "value", - "type": "number", - "description": "" - } - ], - "sourceFile": "src/schemas/output.ts" - }, - { - "name": "OutputInfo", - "kind": "object", - "description": "Detailed information about a UTXO including value, script type, and any inscriptions or runes it contains.", - "properties": [ - { - "name": "address", - "type": "string | null", - "description": "" - }, - { - "name": "indexed", - "type": "boolean", - "description": "" - }, - { - "name": "inscriptions", - "type": "string[] | null", - "description": "" - }, - { - "name": "outpoint", - "type": "string", - "description": "" - }, - { - "name": "runes", - "type": "Record | null", - "description": "" - }, - { - "name": "sat_ranges", - "type": "SatRange[] | null", - "description": "" - }, - { - "name": "script_pubkey", - "type": "string", - "description": "" - }, - { - "name": "spent", - "type": "boolean", - "description": "" - }, - { - "name": "transaction", - "type": "string", - "description": "" - }, - { - "name": "value", - "type": "number", - "description": "" - } - ], - "sourceFile": "src/schemas/output.ts" - }, - { - "name": "OutputType", - "kind": "enum", - "description": "Type of UTXO output (e.g. \"plain\", \"inscription\", \"rune\").", - "values": [ - "any", - "cardinal", - "inscribed", - "runic" - ], - "sourceFile": "src/schemas/output.ts" - }, - { - "name": "RarityType", - "kind": "enum", - "description": "Classification of sat rarity (e.g. \"common\", \"uncommon\", \"rare\", \"epic\", \"legendary\").", - "values": [ - "common", - "epic", - "legendary", - "mythic", - "rare", - "uncommon" - ], - "sourceFile": "src/schemas/sat.ts" - }, - { - "name": "RuneBalance", - "kind": "object", - "description": "Basic information about a rune held by an UTXO.", - "properties": [ - { - "name": "amount", - "type": "number", - "description": "" - }, - { - "name": "divisibility", - "type": "number", - "description": "" - }, - { - "name": "symbol", - "type": "string", - "description": "" - } - ], - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/schemas/rune.ts" - }, - { - "name": "RuneInfo", - "kind": "object", - "description": "Basic information about a rune including its symbol and supply details.", - "properties": [ - { - "name": "block", - "type": "number", - "description": "" - }, - { - "name": "burned", - "type": "number", - "description": "" - }, - { - "name": "divisibility", - "type": "number", - "description": "" - }, - { - "name": "etching", - "type": "string", - "description": "" - }, - { - "name": "mints", - "type": "number", - "description": "" - }, - { - "name": "number", - "type": "number", - "description": "" - }, - { - "name": "premine", - "type": "number", - "description": "" - }, - { - "name": "spaced_rune", - "type": "string", - "description": "" - }, - { - "name": "symbol", - "type": "string | null", - "description": "" - }, - { - "name": "terms", - "type": "RuneTerms", - "description": "" - }, - { - "name": "timestamp", - "type": "number", - "description": "" - }, - { - "name": "turbo", - "type": "boolean", - "description": "" - } - ], - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/schemas/rune.ts" - }, - { - "name": "RuneResponse", - "kind": "object", - "description": "Detailed rune information including minting status and parent.", - "properties": [ - { - "name": "entry", - "type": "RuneInfo", - "description": "" - }, - { - "name": "id", - "type": "string", - "description": "" - }, - { - "name": "mintable", - "type": "boolean", - "description": "" - }, - { - "name": "parent", - "type": "string | null", - "description": "" - } - ], - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/schemas/rune.ts" - }, - { - "name": "RunesResponse", - "kind": "object", - "description": "Paginated response containing a list of runes and metadata.", - "properties": [ - { - "name": "entries", - "type": "[string, RuneInfo][]", - "description": "" - }, - { - "name": "more", - "type": "boolean", - "description": "" - }, - { - "name": "next", - "type": "number | null", - "description": "" - }, - { - "name": "prev", - "type": "number | null", - "description": "" - } - ], - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/schemas/rune.ts" - }, - { - "name": "SatInfo", - "kind": "object", - "description": "Information about a specific satoshi including its number, timestamp, and rarity classification.", - "properties": [ - { - "name": "address", - "type": "string | null", - "description": "" - }, - { - "name": "block", - "type": "number", - "description": "" - }, - { - "name": "charms", - "type": "CharmType[]", - "description": "" - }, - { - "name": "cycle", - "type": "number", - "description": "" - }, - { - "name": "decimal", - "type": "string", - "description": "" - }, - { - "name": "degree", - "type": "string", - "description": "" - }, - { - "name": "epoch", - "type": "number", - "description": "" - }, - { - "name": "inscriptions", - "type": "string[]", - "description": "" - }, - { - "name": "name", - "type": "string", - "description": "" - }, - { - "name": "number", - "type": "number", - "description": "" - }, - { - "name": "offset", - "type": "number", - "description": "" - }, - { - "name": "percentile", - "type": "string", - "description": "" - }, - { - "name": "period", - "type": "number", - "description": "" - }, - { - "name": "rarity", - "type": "RarityType", - "description": "" - }, - { - "name": "satpoint", - "type": "string | null", - "description": "" - }, - { - "name": "timestamp", - "type": "number", - "description": "" - } - ], - "sourceFile": "src/schemas/sat.ts" - }, - { - "name": "ServerStatus", - "kind": "object", - "description": "Current status information about the ordinals server including version, height and indexing progress.", - "properties": [ - { - "name": "address_index", - "type": "boolean", - "description": "" - }, - { - "name": "blessed_inscriptions", - "type": "number", - "description": "" - }, - { - "name": "chain", - "type": "string", - "description": "" - }, - { - "name": "cursed_inscriptions", - "type": "number", - "description": "" - }, - { - "name": "height", - "type": "number", - "description": "" - }, - { - "name": "initial_sync_time", - "type": "Time", - "description": "" - }, - { - "name": "inscriptions", - "type": "number", - "description": "" - }, - { - "name": "lost_sats", - "type": "number", - "description": "" - }, - { - "name": "minimum_rune_for_next_block", - "type": "string | null", - "description": "" - }, - { - "name": "rune_index", - "type": "boolean", - "description": "" - }, - { - "name": "runes", - "type": "number", - "description": "" - }, - { - "name": "sat_index", - "type": "boolean", - "description": "" - }, - { - "name": "started", - "type": "string", - "description": "" - }, - { - "name": "transaction_index", - "type": "boolean", - "description": "" - }, - { - "name": "unrecoverably_reorged", - "type": "boolean", - "description": "" - }, - { - "name": "uptime", - "type": "Time", - "description": "" - } - ], - "sourceFile": "src/schemas/status.ts" - }, - { - "name": "Time", - "kind": "object", - "description": "Type defined in src/schemas/status.ts", - "properties": [ - { - "name": "nanos", - "type": "number", - "description": "" - }, - { - "name": "secs", - "type": "number", - "description": "" - } - ], - "sourceFile": "src/schemas/status.ts" - }, - { - "name": "Transaction", - "kind": "object", - "description": "Bitcoin transaction data including version, locktime, inputs and outputs.", - "properties": [ - { - "name": "input", - "type": "Input[]", - "description": "" - }, - { - "name": "lock_time", - "type": "number", - "description": "" - }, - { - "name": "output", - "type": "Output[]", - "description": "" - }, - { - "name": "version", - "type": "number", - "description": "" - } - ], - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/schemas/transaction.ts" - }, - { - "name": "TransactionInfo", - "kind": "object", - "description": "Extended transaction information including block details, timestamp and inscription data.", - "properties": [ - { - "name": "chain", - "type": "string", - "description": "" - }, - { - "name": "etching", - "type": "string | null", - "description": "" - }, - { - "name": "inscription_count", - "type": "number", - "description": "" - }, - { - "name": "transaction", - "type": "Transaction", - "description": "" - }, - { - "name": "txid", - "type": "string", - "description": "" - } - ], - "sourceFile": "/Users/gole/Desktop/ord-js/ord-js/src/schemas/transaction.ts" - } - ] -} \ No newline at end of file From 5380468be94a5252cd6f5444ece93a6e4a2733ac Mon Sep 17 00:00:00 2001 From: gmemez Date: Fri, 7 Feb 2025 01:27:11 +0700 Subject: [PATCH 6/6] fix github btn --- docs/generateHtml.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/generateHtml.ts b/docs/generateHtml.ts index c938514..7efbd35 100644 --- a/docs/generateHtml.ts +++ b/docs/generateHtml.ts @@ -75,7 +75,7 @@ function generateHtml() {