@iflow-mcp/kdcokenny-lsbible 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,529 @@
1
+ # LSBible SDK for TypeScript
2
+
3
+ Structured, type-safe Bible API client for the Legacy Standard Bible (LSB).
4
+
5
+ ## Features
6
+
7
+ - **100% Type-Safe** - Full TypeScript support with Zod validation
8
+ - **Structured Parameters** - No string parsing! Use `client.getVerse(BookName.JOHN, 3, 16)`
9
+ - **Complete Validation** - All 66 books with chapter/verse validation
10
+ - **Rich Formatting** - Preserves red-letter text, italics, bold, small-caps
11
+ - **Built-in Caching** - Configurable TTL-based response cache
12
+ - **Modern Runtime Support** - Works with Node.js 18+, Bun, and Deno
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ # Using npm
18
+ npm install lsbible
19
+
20
+ # Using pnpm
21
+ pnpm add lsbible
22
+
23
+ # Using bun
24
+ bun add lsbible
25
+ ```
26
+
27
+ ## MCP Server
28
+
29
+ This SDK also includes a **Model Context Protocol (MCP) server** for integration with AI coding assistants like Cursor, Claude Code, VS Code, and more.
30
+
31
+ > **🤖 For MCP Server Installation:** To use LSBible with AI coding tools, see the **[MCP Installation Guide →](./mcp/README.md)** with step-by-step instructions for 20+ supported clients.
32
+
33
+ **Quick Install Examples:**
34
+
35
+ ```sh
36
+ # Claude Code (remote)
37
+ claude mcp add --transport http lsbible https://lsbible.kdco.dev/mcp
38
+
39
+ # Claude Code (local)
40
+ claude mcp add lsbible -- npx -y lsbible-mcp
41
+
42
+ # Cursor/VS Code/etc. (see full guide)
43
+ # Add to your MCP config file - see mcp/README.md for details
44
+ ```
45
+
46
+ ## Quick Start
47
+
48
+ ```typescript
49
+ import { LSBibleClient, BookName } from "lsbible";
50
+
51
+ const client = new LSBibleClient();
52
+
53
+ // Get a single verse (type-safe with enum)
54
+ const verse = await client.getVerse(BookName.JOHN, 3, 16);
55
+ console.log(verse.verses[0].plainText);
56
+ // Output: "For God so loved the world, that He gave His only Son..."
57
+
58
+ // Get a passage range
59
+ const passage = await client.getPassage(
60
+ BookName.JOHN, 3, 16,
61
+ BookName.JOHN, 3, 18
62
+ );
63
+ console.log(`Got ${passage.verseCount} verses`);
64
+
65
+ // Get an entire chapter
66
+ const chapter = await client.getChapter(BookName.PSALMS, 23);
67
+ console.log(`Psalm 23 has ${chapter.verseCount} verses`);
68
+
69
+ // Search for text
70
+ const results = await client.search("love");
71
+ console.log(`Found ${results.matchCount} matches in ${results.passageCount} passages`);
72
+ ```
73
+
74
+ ## Design Philosophy
75
+
76
+ ### Structured Parameters Over String Parsing
77
+
78
+ This SDK prioritizes explicit, structured parameters over string-based references:
79
+
80
+ ```typescript
81
+ // ✅ GOOD - Structured, type-safe, validated
82
+ client.getVerse(BookName.JOHN, 3, 16);
83
+
84
+ // ❌ AVOID - String parsing (error-prone, less type-safe)
85
+ client.getVerse("John 3:16"); // NOT SUPPORTED
86
+ ```
87
+
88
+ **Why Structured Parameters?**
89
+
90
+ 1. **Type Safety** - IDE autocomplete for all 66 books
91
+ 2. **Early Validation** - Catch errors before API calls
92
+ 3. **No Parsing Ambiguity** - Clear, explicit parameters
93
+ 4. **Better Testing** - Easy to generate test cases programmatically
94
+ 5. **Language Agnostic** - Works consistently across all SDKs
95
+
96
+ ## API Reference
97
+
98
+ ### LSBibleClient
99
+
100
+ ```typescript
101
+ import { LSBibleClient, MemoryCacheProvider } from "lsbible";
102
+
103
+ const client = new LSBibleClient({
104
+ cache: {
105
+ provider: new MemoryCacheProvider(), // Optional cache provider
106
+ ttl: {
107
+ verse: 2592000, // 30 days (default)
108
+ passage: 2592000, // 30 days (default)
109
+ chapter: 2592000, // 30 days (default)
110
+ search: 604800, // 7 days (default)
111
+ }
112
+ },
113
+ timeout: 30, // Request timeout in seconds (default: 30)
114
+ buildId: undefined, // Optional build ID (auto-detected if not provided)
115
+ headers: {}, // Optional custom headers
116
+ });
117
+ ```
118
+
119
+ ### Methods
120
+
121
+ #### `getVerse(book, chapter, verse)`
122
+
123
+ Get a specific verse with validated parameters.
124
+
125
+ ```typescript
126
+ // Using enum (recommended)
127
+ const verse = await client.getVerse(BookName.JOHN, 3, 16);
128
+
129
+ // Using string (validated at runtime)
130
+ const verse = await client.getVerse("John", 3, 16);
131
+
132
+ // Access structured data
133
+ for (const v of verse.verses) {
134
+ console.log(`${v.reference.toString()}: ${v.plainText}`);
135
+
136
+ // Access formatting
137
+ for (const segment of v.segments) {
138
+ if (segment.isRedLetter) {
139
+ console.log(`Jesus said: "${segment.text}"`);
140
+ }
141
+ }
142
+ }
143
+ ```
144
+
145
+ #### `getPassage(fromBook, fromChapter, fromVerse, toBook, toChapter, toVerse)`
146
+
147
+ Get a passage spanning multiple verses.
148
+
149
+ ```typescript
150
+ // Get John 3:16-18
151
+ const passage = await client.getPassage(
152
+ BookName.JOHN, 3, 16,
153
+ BookName.JOHN, 3, 18
154
+ );
155
+
156
+ console.log(`Title: ${passage.title}`);
157
+ console.log(`Verses: ${passage.verseCount}`);
158
+ console.log(`Single verse? ${passage.isSingleVerse}`);
159
+ ```
160
+
161
+ #### `getChapter(book, chapter)`
162
+
163
+ Get an entire chapter.
164
+
165
+ ```typescript
166
+ // Get all of Psalm 23
167
+ const chapter = await client.getChapter(BookName.PSALMS, 23);
168
+
169
+ console.log(`Psalm 23 has ${chapter.verseCount} verses`);
170
+
171
+ for (const verse of chapter.verses) {
172
+ console.log(` ${verse.verseNumber}. ${verse.plainText}`);
173
+ }
174
+ ```
175
+
176
+ #### `search(query)`
177
+
178
+ Search for passages containing text.
179
+
180
+ ```typescript
181
+ const results = await client.search("love");
182
+
183
+ console.log(`Found ${results.matchCount} matches`);
184
+ console.log(`Passages: ${results.passageCount}`);
185
+ console.log(`Total verses: ${results.totalVerses}`);
186
+
187
+ // Search results include metadata (for text searches)
188
+ if (results.hasSearchMetadata) {
189
+ console.log(`Total results: ${results.totalCount}`);
190
+ console.log(`Filtered: ${results.filteredCount}`);
191
+ console.log(`By book:`, results.countsByBook);
192
+ }
193
+
194
+ // Iterate through results
195
+ for (const passage of results.passages) {
196
+ console.log(`\n${passage.title}`);
197
+ for (const verse of passage.verses) {
198
+ console.log(` ${verse.plainText}`);
199
+ }
200
+ }
201
+ ```
202
+
203
+ #### `clearCache()`
204
+
205
+ Clear the response cache (only available with `MemoryCacheProvider`).
206
+
207
+ ```typescript
208
+ client.clearCache();
209
+ ```
210
+
211
+ ## Caching
212
+
213
+ The SDK supports pluggable caching through the `CacheProvider` interface, allowing you to choose the right caching strategy for your deployment environment.
214
+
215
+ ### Built-in Cache Providers
216
+
217
+ **MemoryCacheProvider** - In-memory caching with TTL support
218
+ - ✅ Local development, testing, single-process apps
219
+ - ❌ Multi-process apps, Cloudflare Workers, high-traffic production
220
+
221
+ **NoopCacheProvider** - Disables caching entirely
222
+ - Useful for debugging or when caching isn't beneficial
223
+
224
+ **CloudflareCacheProvider** - Edge caching for Cloudflare Workers
225
+ - Available in the [MCP Server implementation](../../apps/mcp-server/src/cache/cloudflare.ts)
226
+
227
+ ### Cache Configuration
228
+
229
+ ```typescript
230
+ import { LSBibleClient, MemoryCacheProvider, CacheTTL } from "lsbible";
231
+
232
+ const client = new LSBibleClient({
233
+ cache: {
234
+ provider: new MemoryCacheProvider(),
235
+ ttl: {
236
+ verse: CacheTTL.BIBLE_CONTENT, // 30 days
237
+ passage: CacheTTL.BIBLE_CONTENT, // 30 days
238
+ chapter: CacheTTL.BIBLE_CONTENT, // 30 days
239
+ search: CacheTTL.SEARCH_RESULTS, // 7 days
240
+ }
241
+ }
242
+ });
243
+ ```
244
+
245
+ **Recommended TTL constants:**
246
+ - `CacheTTL.BIBLE_CONTENT` (30 days) - Bible text is immutable
247
+ - `CacheTTL.SEARCH_RESULTS` (7 days) - May change with API updates
248
+ - `CacheTTL.STATIC` (1 year) - Never changes
249
+
250
+ ### Custom Cache Providers
251
+
252
+ Implement the `CacheProvider` interface for custom backends like Redis, Memcached, or DynamoDB:
253
+
254
+ ```typescript
255
+ interface CacheProvider {
256
+ get<T>(key: string): Promise<T | undefined>;
257
+ set<T>(key: string, value: T, ttl: number): Promise<void>;
258
+ }
259
+ ```
260
+
261
+ **Complete examples:**
262
+ - [Memory Cache](./examples/cache-memory.ts) - Demonstrates cache hits/misses and manual clearing
263
+ - [Redis Cache](./examples/cache-redis.ts) - Full Redis implementation with ioredis
264
+ - [Custom Cache](./examples/cache-custom.ts) - Template for building your own cache provider
265
+
266
+ ### Cache Keys
267
+
268
+ The SDK uses these cache key patterns:
269
+ - `verse:{book} {chapter}:{verse}` - Single verses
270
+ - `passage:{normalized query}` - Passage ranges
271
+ - `chapter:{book} {chapter}` - Full chapters
272
+ - `search:{query}` - Text searches
273
+
274
+ ## Type System
275
+
276
+ ### BookName Enum
277
+
278
+ All 66 Bible books available as enum values:
279
+
280
+ ```typescript
281
+ import { BookName } from "lsbible";
282
+
283
+ // Old Testament
284
+ BookName.GENESIS
285
+ BookName.EXODUS
286
+ // ... through ...
287
+ BookName.MALACHI
288
+
289
+ // New Testament
290
+ BookName.MATTHEW
291
+ BookName.MARK
292
+ // ... through ...
293
+ BookName.REVELATION
294
+ ```
295
+
296
+ ### VerseReference
297
+
298
+ ```typescript
299
+ interface VerseReference {
300
+ bookNumber: number; // 1-66
301
+ chapter: number; // Validated against book
302
+ verse: number; // Validated against chapter
303
+ readonly bookName: BookName; // Computed property
304
+ toString(): string; // e.g., "John 3:16"
305
+ }
306
+ ```
307
+
308
+ ### TextSegment
309
+
310
+ ```typescript
311
+ interface TextSegment {
312
+ text: string;
313
+ isRedLetter: boolean; // Words of Jesus
314
+ isItalic: boolean; // Italicized clarifications
315
+ isBold: boolean; // Bold text
316
+ isSmallCaps: boolean; // LORD (Yahweh)
317
+ }
318
+ ```
319
+
320
+ ### VerseContent
321
+
322
+ ```typescript
323
+ interface VerseContent {
324
+ reference: VerseReference;
325
+ verseNumber: number;
326
+ segments: TextSegment[];
327
+ hasSubheading: boolean;
328
+ subheadingText: string | null;
329
+ isPoetry: boolean;
330
+ isProse: boolean;
331
+ chapterStart: boolean;
332
+ readonly plainText: string; // Computed property
333
+ readonly formattedText: string; // Computed property
334
+ }
335
+ ```
336
+
337
+ ### Passage
338
+
339
+ ```typescript
340
+ interface Passage {
341
+ fromRef: VerseReference;
342
+ toRef: VerseReference;
343
+ title: string;
344
+ verses: VerseContent[];
345
+ readonly isSingleVerse: boolean; // Computed property
346
+ readonly verseCount: number; // Computed property
347
+ }
348
+ ```
349
+
350
+ ### SearchResponse
351
+
352
+ ```typescript
353
+ interface SearchResponse {
354
+ query: string;
355
+ matchCount: number;
356
+ passages: Passage[];
357
+ durationMs: number;
358
+ timestamp: number;
359
+
360
+ // Optional (for text searches only)
361
+ totalCount?: number;
362
+ filteredCount?: number;
363
+ countsByBook?: Record<string, number>;
364
+ countsBySection?: Record<string, number>;
365
+
366
+ // Computed properties
367
+ readonly passageCount: number;
368
+ readonly totalVerses: number;
369
+ readonly hasSearchMetadata: boolean;
370
+ }
371
+ ```
372
+
373
+ ## Error Handling
374
+
375
+ ```typescript
376
+ import { LSBibleClient, BookName, InvalidReferenceError, APIError } from "lsbible";
377
+
378
+ const client = new LSBibleClient();
379
+
380
+ try {
381
+ // Invalid chapter (John only has 21 chapters)
382
+ await client.getVerse(BookName.JOHN, 99, 1);
383
+ } catch (error) {
384
+ if (error instanceof InvalidReferenceError) {
385
+ console.error(`Invalid reference: ${error.message}`);
386
+ // Output: "John only has 21 chapters, but chapter 99 was requested"
387
+ }
388
+ }
389
+
390
+ try {
391
+ // Invalid verse (John 3 only has 36 verses)
392
+ await client.getVerse(BookName.JOHN, 3, 999);
393
+ } catch (error) {
394
+ if (error instanceof InvalidReferenceError) {
395
+ console.error(`Invalid reference: ${error.message}`);
396
+ // Output: "John 3 only has 36 verses, but verse 999 was requested"
397
+ }
398
+ }
399
+
400
+ try {
401
+ // Invalid book name
402
+ await client.getVerse("NotABook", 1, 1);
403
+ } catch (error) {
404
+ if (error instanceof InvalidReferenceError) {
405
+ console.error(`Invalid reference: ${error.message}`);
406
+ // Output: "Unknown book: NotABook"
407
+ }
408
+ }
409
+
410
+ try {
411
+ // API failure
412
+ await client.search("something");
413
+ } catch (error) {
414
+ if (error instanceof APIError) {
415
+ console.error(`API error: ${error.message}`);
416
+ }
417
+ }
418
+ ```
419
+
420
+ ## Bible Structure Data
421
+
422
+ The SDK includes complete validation data for all 66 books:
423
+
424
+ - **Old Testament:** 39 books (Genesis through Malachi)
425
+ - **New Testament:** 27 books (Matthew through Revelation)
426
+ - **Total:** 1,189 chapters, 31,102 verses
427
+
428
+ ```typescript
429
+ import { BIBLE_STRUCTURE, BOOK_NAMES, BOOK_NUMBERS } from "lsbible";
430
+
431
+ // Get book info
432
+ const johnInfo = BIBLE_STRUCTURE[43];
433
+ console.log(johnInfo.name); // "John"
434
+ console.log(johnInfo.chapters); // 21
435
+ console.log(johnInfo.verses[2]); // Chapter 3 has 36 verses
436
+
437
+ // Lookup book number
438
+ const bookNum = BOOK_NUMBERS["john"]; // 43
439
+
440
+ // Lookup book name
441
+ const bookName = BOOK_NAMES[43]; // "John"
442
+ ```
443
+
444
+ ## Runtime Support
445
+
446
+ The SDK is designed to work across modern JavaScript runtimes:
447
+
448
+ - **Node.js** 18.0.0 or higher (native fetch support)
449
+ - **Bun** (optimized build performance)
450
+ - **Deno** (works out of the box)
451
+
452
+ ## Examples
453
+
454
+ ### Example 1: Display a Verse with Formatting
455
+
456
+ ```typescript
457
+ import { LSBibleClient, BookName } from "lsbible";
458
+
459
+ const client = new LSBibleClient();
460
+ const verse = await client.getVerse(BookName.JOHN, 3, 16);
461
+
462
+ for (const v of verse.verses) {
463
+ console.log(`\n${v.reference.toString()}\n`);
464
+
465
+ for (const segment of v.segments) {
466
+ let text = segment.text;
467
+ if (segment.isRedLetter) text = `\x1b[31m${text}\x1b[0m`; // Red
468
+ if (segment.isItalic) text = `\x1b[3m${text}\x1b[0m`; // Italic
469
+ if (segment.isSmallCaps) text = text.toUpperCase(); // Small caps -> uppercase
470
+ process.stdout.write(text + " ");
471
+ }
472
+ console.log("\n");
473
+ }
474
+ ```
475
+
476
+ ### Example 2: Find All Occurrences of a Word
477
+
478
+ ```typescript
479
+ import { LSBibleClient } from "lsbible";
480
+
481
+ const client = new LSBibleClient();
482
+ const results = await client.search("faith");
483
+
484
+ console.log(`Found "${results.query}" ${results.matchCount} times\n`);
485
+
486
+ for (const passage of results.passages) {
487
+ for (const verse of passage.verses) {
488
+ console.log(`${verse.reference.toString()}: ${verse.plainText}`);
489
+ }
490
+ }
491
+ ```
492
+
493
+ ### Example 3: Read an Entire Book
494
+
495
+ ```typescript
496
+ import { LSBibleClient, BookName, BIBLE_STRUCTURE } from "lsbible";
497
+
498
+ const client = new LSBibleClient();
499
+ const bookNum = 57; // Philemon
500
+ const bookInfo = BIBLE_STRUCTURE[bookNum];
501
+
502
+ console.log(`Reading ${bookInfo.name}\n`);
503
+
504
+ for (let chapter = 1; chapter <= bookInfo.chapters; chapter++) {
505
+ const passage = await client.getChapter(BookName.PHILEMON, chapter);
506
+
507
+ console.log(`\nChapter ${chapter}\n`);
508
+
509
+ for (const verse of passage.verses) {
510
+ console.log(`${verse.verseNumber}. ${verse.plainText}`);
511
+ }
512
+ }
513
+ ```
514
+
515
+ ## Contributing
516
+
517
+ This SDK is part of the LSBible monorepo. Contributions are welcome!
518
+
519
+ See the main repository for contribution guidelines: https://github.com/kdcokenny/lsbible
520
+
521
+ ## License
522
+
523
+ MIT License - See LICENSE file for details.
524
+
525
+ ## Related
526
+
527
+ - [Python SDK](../python-sdk) - Official Python implementation
528
+ - [API Documentation](../../.specs/SPEC.md) - Complete SDK specification
529
+ - [LSBible Website](https://read.lsbible.org) - Read the Legacy Standard Bible online