From 086f58ac42f5bed7ba9fd7fd68fa2563f3d1ef27 Mon Sep 17 00:00:00 2001 From: Basit Minhas Date: Mon, 2 Feb 2026 12:59:29 +0500 Subject: [PATCH] feat(api): add verses/by_range endpoint support This commit adds support for the new `/api/v4/verses/by_range` endpoint to the JS SDK. --- packages/api/mocks/handlers.ts | 21 ++++++++++++++++++ packages/api/src/sdk/verses.ts | 32 ++++++++++++++++++++++++++++ packages/api/src/types/api/Tafsir.ts | 7 ++++++ packages/api/test/verses.test.ts | 25 ++++++++++++++++++++++ 4 files changed, 85 insertions(+) diff --git a/packages/api/mocks/handlers.ts b/packages/api/mocks/handlers.ts index a6c99d9..bb2bae1 100644 --- a/packages/api/mocks/handlers.ts +++ b/packages/api/mocks/handlers.ts @@ -45,6 +45,27 @@ export const handlers = [ }, ), + http.get( + "https://apis.quran.foundation/content/api/v4/verses/by_range", + ({ request }) => { + return HttpResponse.json({ + verses: [ + { + id: 1, + verse_number: 1, + page_number: 1, + verse_key: "1:1", + juz_number: 1, + hizb_number: 1, + rub_number: 1, + sajdah_type: null, + sajdah_number: null, + }, + ], + }); + }, + ), + http.get( "https://apis.quran.foundation/content/api/v4/chapters", ({ request }) => { diff --git a/packages/api/src/sdk/verses.ts b/packages/api/src/sdk/verses.ts index 4d030b9..d4b383d 100644 --- a/packages/api/src/sdk/verses.ts +++ b/packages/api/src/sdk/verses.ts @@ -62,6 +62,38 @@ export class QuranVerses { return verse; } + /** + * Get verses by range. + * @param {VerseKey} from start verse key (e.g., "1:1") + * @param {VerseKey} to end verse key (e.g., "1:7") + * @param {GetVerseOptions} options + * @example + * client.verses.findByRange('1:1', '1:7') + */ + async findByRange( + from: VerseKey, + to: VerseKey, + options?: GetVerseOptions, + ): Promise { + // We could validate keys here, but the API will also valid it. + // simpler to just pass through for now, or use isValidVerseKey if desired. + if (!isValidVerseKey(from) || !isValidVerseKey(to)) { + throw new Error("Invalid verse key"); + } + + const { verses } = await this.fetcher.fetch<{ verses: Verse[] }>( + "/content/api/v4/verses/by_range", + { + words: false, // verses-specific default + ...options, + from, + to, + }, + ); + + return verses; + } + /** * Get verses by chapter. * @param {ChapterId} id chapter id, minimum 1, maximum 114 diff --git a/packages/api/src/types/api/Tafsir.ts b/packages/api/src/types/api/Tafsir.ts index 83f7aaa..ccad404 100644 --- a/packages/api/src/types/api/Tafsir.ts +++ b/packages/api/src/types/api/Tafsir.ts @@ -4,4 +4,11 @@ export interface Tafsir { text?: string; resourceName?: string; languageName?: string; + slug?: string; + languageId?: number; + groupVerseKeyFrom?: string; + groupVerseKeyTo?: string; + groupTafsirId?: number; + startVerseId?: number; + endVerseId?: number; } diff --git a/packages/api/test/verses.test.ts b/packages/api/test/verses.test.ts index 471c913..866fcc1 100644 --- a/packages/api/test/verses.test.ts +++ b/packages/api/test/verses.test.ts @@ -60,6 +60,31 @@ describe("Verses API", () => { }); }); + describe("findByRange()", () => { + it("should return verses for valid range", async () => { + const response = await testClient.verses.findByRange( + VALID_VERSE_KEY, + VALID_VERSE_KEY, + ); + expect(response).toBeInstanceOf(Array); + expect(response).toBeDefined(); + }); + + it("should throw error when 'from' key is invalid", async () => { + await expect( + // @ts-expect-error - testing invalid verse key + testClient.verses.findByRange(INVALID_VERSE_KEY, VALID_VERSE_KEY), + ).rejects.toThrowError(); + }); + + it("should throw error when 'to' key is invalid", async () => { + await expect( + // @ts-expect-error - testing invalid verse key + testClient.verses.findByRange(VALID_VERSE_KEY, INVALID_VERSE_KEY), + ).rejects.toThrowError(); + }); + }); + describe("findByPage()", () => { it("should return an array of verses for valid page", async () => { const response = await testClient.verses.findByPage(VALID_PAGE_NUMBER);