diff --git a/docs/generateHtml.ts b/docs/generateHtml.ts index a9121df..3285b76 100644 --- a/docs/generateHtml.ts +++ b/docs/generateHtml.ts @@ -2,6 +2,7 @@ import fs from 'fs'; import path from 'path'; function generateHtml() { + const config = { repoAddress: 'https://github.com/raphjaph/ordapi', version: 'v0.0.5' diff --git a/src/api.ts b/src/api.ts index 7a45ed7..b5a53ca 100644 --- a/src/api.ts +++ b/src/api.ts @@ -12,9 +12,11 @@ const api = { 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; diff --git a/src/client.ts b/src/client.ts index de0872e..d898761 100644 --- a/src/client.ts +++ b/src/client.ts @@ -91,6 +91,34 @@ export class OrdClient { return result.data; } + private async fetchPost( + endpoint: string, + payload: P, + schema: T, + ): Promise> { + const response = await fetch(`${this.baseUrl}${endpoint}`, { + method: 'POST', + headers: { + ...this.headers, + 'Content-Type': 'application/json', + }, + body: JSON.stringify(payload), + }); + + if (!response.ok) { + throw new Error(`API request failed: ${response.statusText}`); + } + + const data = await response.json(); + const result = schema.safeParse(data); + + if (!result.success) { + throw new Error(`Validation error: ${result.error.message}`); + } + + return result.data; + } + /** * Retrieves information about a specific address including its outputs, * inscriptions, and rune balances. @@ -234,6 +262,19 @@ export class OrdClient { return this.fetch(api.getInscriptions, InscriptionsResponseSchema); } + /** + * Retrieves information about multiple inscriptions by their IDs. + * + * @param {string[]} ids - Array of inscription IDs to fetch + */ + async getInscriptionsByIds(ids: string[]): Promise { + return this.fetchPost( + api.getInscriptionsByIds, + ids, + z.array(InscriptionInfoSchema), + ); + } + /** * Gets inscriptions for a specific page number in paginated results. * @@ -405,6 +446,15 @@ export class OrdClient { return this.fetch(api.getOutputAssets(outpoint), OutputAssetsSchema); } + /** + * Gets information about multiple UTXOs. + * + * @param {string[]} outpoints - Array of outpoints to fetch + */ + async getOutputs(outpoints: string[]): Promise { + return this.fetchPost(api.getOutputs, outpoints, z.array(OutputInfoSchema)); + } + /** * Gets all UTXOs for a specific address, optionally filtered by type. * diff --git a/src/test/integration/api.test.ts b/src/test/integration/api.test.ts index fcdb3a8..c2970a6 100644 --- a/src/test/integration/api.test.ts +++ b/src/test/integration/api.test.ts @@ -325,6 +325,43 @@ describe('API Integration Tests', () => { ); }); + describe('getInscriptionsByIds', () => { + test( + 'fetches multiple inscriptions successfully', + async () => { + const inscriptions = await client.getInscriptionsByIds([ + SAMPLE_INSCRIPTION_ID, + SAMPLE_CHILD_ID, + ]); + expect(Array.isArray(inscriptions)).toBe(true); + expect(inscriptions.length).toBe(2); + expect(inscriptions[0].id).toBe(SAMPLE_INSCRIPTION_ID); + expect(inscriptions[1].id).toBe(SAMPLE_CHILD_ID); + }, + TIMEOUT, + ); + + test( + 'handles server error', + async () => { + expect( + invalidClient.getInscriptionsByIds([SAMPLE_INSCRIPTION_ID]), + ).rejects.toThrow(); + }, + TIMEOUT, + ); + + test( + 'handles empty array', + async () => { + const inscriptions = await client.getInscriptionsByIds([]); + expect(Array.isArray(inscriptions)).toBe(true); + expect(inscriptions.length).toBe(0); + }, + TIMEOUT, + ); + }); + describe('getOutput', () => { test( 'fetches output successfully', @@ -354,6 +391,40 @@ describe('API Integration Tests', () => { ); }); + describe('getOutputs', () => { + test( + 'fetches multiple outputs successfully', + async () => { + const outpoints = [SAMPLE_OUTPOINT_A, SAMPLE_OUTPOINT_B]; + const outputs = await client.getOutputs(outpoints); + expect(Array.isArray(outputs)).toBe(true); + expect(outputs[0].outpoint).toBe(SAMPLE_OUTPOINT_A); + expect(outputs[1].outpoint).toBe(SAMPLE_OUTPOINT_B); + }, + TIMEOUT, + ); + + test( + 'handles empty array', + async () => { + const outputs = await client.getOutputs([]); + expect(Array.isArray(outputs)).toBe(true); + expect(outputs.length).toBe(0); + }, + TIMEOUT, + ); + + test( + 'handles server error', + async () => { + expect( + invalidClient.getOutputs([SAMPLE_OUTPOINT_A, SAMPLE_OUTPOINT_B]), + ).rejects.toThrow(); + }, + TIMEOUT, + ); + }); + describe('getOutputsByAddress', () => { test( 'fetches outputs by address successfully',