@ambry/scripture 0.0.0-stage → 0.1.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.
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.scriptureLanguages = exports.findScriptureReferences = exports.parseScriptureReference = exports.scriptureBooks = void 0;
4
+ var books_js_1 = require("./books.js");
5
+ Object.defineProperty(exports, "scriptureBooks", { enumerable: true, get: function () { return books_js_1.scriptureBooks; } });
6
+ var references_js_1 = require("./references.js");
7
+ Object.defineProperty(exports, "parseScriptureReference", { enumerable: true, get: function () { return references_js_1.parseScriptureReference; } });
8
+ Object.defineProperty(exports, "findScriptureReferences", { enumerable: true, get: function () { return references_js_1.findScriptureReferences; } });
9
+ Object.defineProperty(exports, "scriptureLanguages", { enumerable: true, get: function () { return references_js_1.scriptureLanguages; } });
@@ -0,0 +1 @@
1
+ {"type":"commonjs"}
@@ -0,0 +1,32 @@
1
+ import { type ScriptureBookCode } from './books.js';
2
+ export type ScriptureLanguage = 'english' | 'greek' | 'latin';
3
+ export type ScriptureReference = {
4
+ book: string;
5
+ bookCode: ScriptureBookCode;
6
+ chapter: number;
7
+ firstVerse?: number;
8
+ lastVerse?: number;
9
+ language?: ScriptureLanguage;
10
+ };
11
+ export type ParseScriptureOptions = {
12
+ maxVerses?: number;
13
+ };
14
+ export type FindScriptureOptions = ParseScriptureOptions & {
15
+ maxReferences?: number;
16
+ };
17
+ export declare const scriptureLanguages: {
18
+ readonly english: {
19
+ readonly label: "English";
20
+ readonly field: "english_text";
21
+ };
22
+ readonly greek: {
23
+ readonly label: "Greek";
24
+ readonly field: "greek_text";
25
+ };
26
+ readonly latin: {
27
+ readonly label: "Latin";
28
+ readonly field: "latin_text";
29
+ };
30
+ };
31
+ export declare function parseScriptureReference(input: string, options?: ParseScriptureOptions): ScriptureReference | undefined;
32
+ export declare function findScriptureReferences(content: string, options?: FindScriptureOptions): ScriptureReference[];
@@ -0,0 +1,84 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.scriptureLanguages = void 0;
4
+ exports.parseScriptureReference = parseScriptureReference;
5
+ exports.findScriptureReferences = findScriptureReferences;
6
+ const books_js_1 = require("./books.js");
7
+ function positiveLimit(value, name) {
8
+ if (!Number.isSafeInteger(value) || value < 1)
9
+ throw new RangeError(`${name} must be a positive safe integer.`);
10
+ return value;
11
+ }
12
+ exports.scriptureLanguages = {
13
+ english: { label: 'English', field: 'english_text' },
14
+ greek: { label: 'Greek', field: 'greek_text' },
15
+ latin: { label: 'Latin', field: 'latin_text' },
16
+ };
17
+ const languagePattern = 'ENGLISH|ENG|EN|GREEK|GRK|GRC|LATIN|LAT|LA';
18
+ const languageSuffixes = {
19
+ ENGLISH: 'english',
20
+ ENG: 'english',
21
+ EN: 'english',
22
+ GREEK: 'greek',
23
+ GRK: 'greek',
24
+ GRC: 'greek',
25
+ LATIN: 'latin',
26
+ LAT: 'latin',
27
+ LA: 'latin',
28
+ };
29
+ const normalizeBook = (name) => name.toLowerCase().replace(/[\s.]/g, '');
30
+ const bookNames = books_js_1.scriptureBooks.flatMap((book) => [book.name, book.code, ...book.aliases].map((name) => ({ name, book })));
31
+ const escapePattern = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
32
+ const bookPattern = bookNames
33
+ .map(({ name }) => escapePattern(name).replace(/ /g, '\\s*'))
34
+ .sort((a, b) => b.length - a.length)
35
+ .join('|');
36
+ const embeddedReferencePattern = new RegExp(String.raw `(?<![\p{L}\p{N}_])(${bookPattern})\.?\s*(\d{1,3})\s*:\s*(\d{1,3})(?:\s*[-–]\s*(\d{1,3}))?(?:\s+(${languagePattern}))?(?![\p{L}\p{N}_]|\s*[:–-]\s*\d)`, 'giu');
37
+ function parseScriptureReference(input, options = {}) {
38
+ const maxVerses = positiveLimit(options.maxVerses ?? 176, 'maxVerses');
39
+ const match = input
40
+ .trim()
41
+ .match(new RegExp(String.raw `^(.+?)\s*(\d{1,3})(?:\s*:\s*(\d{1,3})(?:\s*[-–]\s*(\d{1,3}))?)?(?:\s+(${languagePattern}))?$`, 'i'));
42
+ if (!match)
43
+ return;
44
+ const book = bookNames.find(({ name }) => normalizeBook(name) === normalizeBook(match[1]))?.book;
45
+ const chapter = Number(match[2]);
46
+ const firstVerse = match[3] ? Number(match[3]) : undefined;
47
+ const lastVerse = match[4] ? Number(match[4]) : firstVerse;
48
+ if (!book || chapter < 1 || chapter > 150)
49
+ return;
50
+ if (firstVerse != null &&
51
+ (firstVerse < 1 || lastVerse > 176 || lastVerse < firstVerse || lastVerse - firstVerse + 1 > maxVerses))
52
+ return;
53
+ return {
54
+ book: book.name,
55
+ bookCode: book.code,
56
+ chapter,
57
+ firstVerse,
58
+ lastVerse,
59
+ language: languageSuffixes[match[5]?.toUpperCase()] ?? 'english',
60
+ };
61
+ }
62
+ function findScriptureReferences(content, options = {}) {
63
+ const maxReferences = positiveLimit(options.maxReferences ?? 10, 'maxReferences');
64
+ positiveLimit(options.maxVerses ?? 176, 'maxVerses');
65
+ const trailingLanguage = content.match(new RegExp(String.raw `\b(${languagePattern})\s*[.!?]?\s*$`, 'i'));
66
+ const defaultLanguage = languageSuffixes[trailingLanguage?.[1].toUpperCase() ?? ''] ?? 'english';
67
+ const references = [];
68
+ const seen = new Set();
69
+ for (const match of content.matchAll(embeddedReferencePattern)) {
70
+ const reference = parseScriptureReference(match[0], options);
71
+ if (!reference)
72
+ continue;
73
+ if (!match[5])
74
+ reference.language = defaultLanguage;
75
+ const key = `${reference.bookCode}:${reference.chapter}:${reference.firstVerse}:${reference.lastVerse}:${reference.language}`;
76
+ if (seen.has(key))
77
+ continue;
78
+ seen.add(key);
79
+ references.push(reference);
80
+ if (references.length === maxReferences)
81
+ break;
82
+ }
83
+ return references;
84
+ }
@@ -0,0 +1,295 @@
1
+ export declare const scriptureBooks: readonly [{
2
+ readonly name: "Genesis";
3
+ readonly code: "gen";
4
+ readonly aliases: readonly ["Gen"];
5
+ }, {
6
+ readonly name: "Exodus";
7
+ readonly code: "exo";
8
+ readonly aliases: readonly ["Ex", "Exod"];
9
+ }, {
10
+ readonly name: "Leviticus";
11
+ readonly code: "lev";
12
+ readonly aliases: readonly ["Lev"];
13
+ }, {
14
+ readonly name: "Numbers";
15
+ readonly code: "num";
16
+ readonly aliases: readonly ["Num"];
17
+ }, {
18
+ readonly name: "Deuteronomy";
19
+ readonly code: "deu";
20
+ readonly aliases: readonly ["Deut"];
21
+ }, {
22
+ readonly name: "Joshua";
23
+ readonly code: "jos";
24
+ readonly aliases: readonly ["Josh"];
25
+ }, {
26
+ readonly name: "Judges";
27
+ readonly code: "jdg";
28
+ readonly aliases: readonly ["Judg"];
29
+ }, {
30
+ readonly name: "Ruth";
31
+ readonly code: "rut";
32
+ readonly aliases: readonly ["Ruth"];
33
+ }, {
34
+ readonly name: "1 Samuel";
35
+ readonly code: "1sa";
36
+ readonly aliases: readonly ["1 Sam"];
37
+ }, {
38
+ readonly name: "2 Samuel";
39
+ readonly code: "2sa";
40
+ readonly aliases: readonly ["2 Sam"];
41
+ }, {
42
+ readonly name: "1 Kings";
43
+ readonly code: "1ki";
44
+ readonly aliases: readonly ["1 Kgs"];
45
+ }, {
46
+ readonly name: "2 Kings";
47
+ readonly code: "2ki";
48
+ readonly aliases: readonly ["2 Kgs"];
49
+ }, {
50
+ readonly name: "1 Chronicles";
51
+ readonly code: "1ch";
52
+ readonly aliases: readonly ["1 Chron"];
53
+ }, {
54
+ readonly name: "2 Chronicles";
55
+ readonly code: "2ch";
56
+ readonly aliases: readonly ["2 Chron"];
57
+ }, {
58
+ readonly name: "Ezra";
59
+ readonly code: "ezr";
60
+ readonly aliases: readonly [];
61
+ }, {
62
+ readonly name: "Nehemiah";
63
+ readonly code: "neh";
64
+ readonly aliases: readonly ["Neh"];
65
+ }, {
66
+ readonly name: "Tobit";
67
+ readonly code: "tob";
68
+ readonly aliases: readonly ["Tob"];
69
+ }, {
70
+ readonly name: "Judith";
71
+ readonly code: "jth";
72
+ readonly aliases: readonly ["Jdt"];
73
+ }, {
74
+ readonly name: "Esther";
75
+ readonly code: "est";
76
+ readonly aliases: readonly [];
77
+ }, {
78
+ readonly name: "Job";
79
+ readonly code: "job";
80
+ readonly aliases: readonly [];
81
+ }, {
82
+ readonly name: "Psalms";
83
+ readonly code: "psa";
84
+ readonly aliases: readonly ["Psalm", "Ps"];
85
+ }, {
86
+ readonly name: "Proverbs";
87
+ readonly code: "pro";
88
+ readonly aliases: readonly ["Prov"];
89
+ }, {
90
+ readonly name: "Ecclesiastes";
91
+ readonly code: "ecc";
92
+ readonly aliases: readonly ["Eccl"];
93
+ }, {
94
+ readonly name: "Song of Songs";
95
+ readonly code: "son";
96
+ readonly aliases: readonly ["Song of Solomon", "Canticles"];
97
+ }, {
98
+ readonly name: "Wisdom";
99
+ readonly code: "wis";
100
+ readonly aliases: readonly [];
101
+ }, {
102
+ readonly name: "Sirach";
103
+ readonly code: "sir";
104
+ readonly aliases: readonly ["Ecclesiasticus"];
105
+ }, {
106
+ readonly name: "Isaiah";
107
+ readonly code: "isa";
108
+ readonly aliases: readonly ["Isa"];
109
+ }, {
110
+ readonly name: "Jeremiah";
111
+ readonly code: "jer";
112
+ readonly aliases: readonly ["Jer"];
113
+ }, {
114
+ readonly name: "Lamentations";
115
+ readonly code: "lam";
116
+ readonly aliases: readonly [];
117
+ }, {
118
+ readonly name: "Baruch";
119
+ readonly code: "bar";
120
+ readonly aliases: readonly [];
121
+ }, {
122
+ readonly name: "Ezekiel";
123
+ readonly code: "eze";
124
+ readonly aliases: readonly ["Ezek"];
125
+ }, {
126
+ readonly name: "Daniel";
127
+ readonly code: "dan";
128
+ readonly aliases: readonly ["Dan"];
129
+ }, {
130
+ readonly name: "Hosea";
131
+ readonly code: "hos";
132
+ readonly aliases: readonly [];
133
+ }, {
134
+ readonly name: "Joel";
135
+ readonly code: "joe";
136
+ readonly aliases: readonly [];
137
+ }, {
138
+ readonly name: "Amos";
139
+ readonly code: "amo";
140
+ readonly aliases: readonly [];
141
+ }, {
142
+ readonly name: "Obadiah";
143
+ readonly code: "oba";
144
+ readonly aliases: readonly [];
145
+ }, {
146
+ readonly name: "Jonah";
147
+ readonly code: "jon";
148
+ readonly aliases: readonly [];
149
+ }, {
150
+ readonly name: "Micah";
151
+ readonly code: "mic";
152
+ readonly aliases: readonly [];
153
+ }, {
154
+ readonly name: "Nahum";
155
+ readonly code: "nah";
156
+ readonly aliases: readonly [];
157
+ }, {
158
+ readonly name: "Habakkuk";
159
+ readonly code: "hab";
160
+ readonly aliases: readonly [];
161
+ }, {
162
+ readonly name: "Zephaniah";
163
+ readonly code: "zep";
164
+ readonly aliases: readonly [];
165
+ }, {
166
+ readonly name: "Haggai";
167
+ readonly code: "hag";
168
+ readonly aliases: readonly [];
169
+ }, {
170
+ readonly name: "Zechariah";
171
+ readonly code: "zec";
172
+ readonly aliases: readonly [];
173
+ }, {
174
+ readonly name: "Malachi";
175
+ readonly code: "mal";
176
+ readonly aliases: readonly [];
177
+ }, {
178
+ readonly name: "1 Maccabees";
179
+ readonly code: "1ma";
180
+ readonly aliases: readonly [];
181
+ }, {
182
+ readonly name: "2 Maccabees";
183
+ readonly code: "2ma";
184
+ readonly aliases: readonly [];
185
+ }, {
186
+ readonly name: "Matthew";
187
+ readonly code: "mat";
188
+ readonly aliases: readonly ["Mt", "Matt"];
189
+ }, {
190
+ readonly name: "Mark";
191
+ readonly code: "mar";
192
+ readonly aliases: readonly ["Mk"];
193
+ }, {
194
+ readonly name: "Luke";
195
+ readonly code: "luk";
196
+ readonly aliases: readonly ["Lk"];
197
+ }, {
198
+ readonly name: "John";
199
+ readonly code: "joh";
200
+ readonly aliases: readonly ["Jn"];
201
+ }, {
202
+ readonly name: "Acts";
203
+ readonly code: "act";
204
+ readonly aliases: readonly [];
205
+ }, {
206
+ readonly name: "Romans";
207
+ readonly code: "rom";
208
+ readonly aliases: readonly ["Rom"];
209
+ }, {
210
+ readonly name: "1 Corinthians";
211
+ readonly code: "1co";
212
+ readonly aliases: readonly ["1 Cor"];
213
+ }, {
214
+ readonly name: "2 Corinthians";
215
+ readonly code: "2co";
216
+ readonly aliases: readonly ["2 Cor"];
217
+ }, {
218
+ readonly name: "Galatians";
219
+ readonly code: "gal";
220
+ readonly aliases: readonly ["Gal"];
221
+ }, {
222
+ readonly name: "Ephesians";
223
+ readonly code: "eph";
224
+ readonly aliases: readonly ["Eph"];
225
+ }, {
226
+ readonly name: "Philippians";
227
+ readonly code: "phi";
228
+ readonly aliases: readonly ["Phil"];
229
+ }, {
230
+ readonly name: "Colossians";
231
+ readonly code: "col";
232
+ readonly aliases: readonly [];
233
+ }, {
234
+ readonly name: "1 Thessalonians";
235
+ readonly code: "1th";
236
+ readonly aliases: readonly ["1 Thess"];
237
+ }, {
238
+ readonly name: "2 Thessalonians";
239
+ readonly code: "2th";
240
+ readonly aliases: readonly ["2 Thess"];
241
+ }, {
242
+ readonly name: "1 Timothy";
243
+ readonly code: "1ti";
244
+ readonly aliases: readonly ["1 Tim"];
245
+ }, {
246
+ readonly name: "2 Timothy";
247
+ readonly code: "2ti";
248
+ readonly aliases: readonly ["2 Tim"];
249
+ }, {
250
+ readonly name: "Titus";
251
+ readonly code: "tit";
252
+ readonly aliases: readonly [];
253
+ }, {
254
+ readonly name: "Philemon";
255
+ readonly code: "phm";
256
+ readonly aliases: readonly ["Philem"];
257
+ }, {
258
+ readonly name: "Hebrews";
259
+ readonly code: "heb";
260
+ readonly aliases: readonly [];
261
+ }, {
262
+ readonly name: "James";
263
+ readonly code: "jam";
264
+ readonly aliases: readonly ["Jas"];
265
+ }, {
266
+ readonly name: "1 Peter";
267
+ readonly code: "1pe";
268
+ readonly aliases: readonly ["1 Pet"];
269
+ }, {
270
+ readonly name: "2 Peter";
271
+ readonly code: "2pe";
272
+ readonly aliases: readonly ["2 Pet"];
273
+ }, {
274
+ readonly name: "1 John";
275
+ readonly code: "1jo";
276
+ readonly aliases: readonly ["1 Jn"];
277
+ }, {
278
+ readonly name: "2 John";
279
+ readonly code: "2jo";
280
+ readonly aliases: readonly ["2 Jn"];
281
+ }, {
282
+ readonly name: "3 John";
283
+ readonly code: "3jo";
284
+ readonly aliases: readonly ["3 Jn"];
285
+ }, {
286
+ readonly name: "Jude";
287
+ readonly code: "jud";
288
+ readonly aliases: readonly [];
289
+ }, {
290
+ readonly name: "Revelation";
291
+ readonly code: "rev";
292
+ readonly aliases: readonly ["Apocalypse"];
293
+ }];
294
+ export type ScriptureBook = (typeof scriptureBooks)[number];
295
+ export type ScriptureBookCode = ScriptureBook['code'];
@@ -0,0 +1,80 @@
1
+ // Canonical names and codes from https://api.ambry.church/openapi.json.
2
+ export const scriptureBooks = [
3
+ { name: 'Genesis', code: 'gen', aliases: ['Gen'] },
4
+ { name: 'Exodus', code: 'exo', aliases: ['Ex', 'Exod'] },
5
+ { name: 'Leviticus', code: 'lev', aliases: ['Lev'] },
6
+ { name: 'Numbers', code: 'num', aliases: ['Num'] },
7
+ { name: 'Deuteronomy', code: 'deu', aliases: ['Deut'] },
8
+ { name: 'Joshua', code: 'jos', aliases: ['Josh'] },
9
+ { name: 'Judges', code: 'jdg', aliases: ['Judg'] },
10
+ { name: 'Ruth', code: 'rut', aliases: ['Ruth'] },
11
+ { name: '1 Samuel', code: '1sa', aliases: ['1 Sam'] },
12
+ { name: '2 Samuel', code: '2sa', aliases: ['2 Sam'] },
13
+ { name: '1 Kings', code: '1ki', aliases: ['1 Kgs'] },
14
+ { name: '2 Kings', code: '2ki', aliases: ['2 Kgs'] },
15
+ { name: '1 Chronicles', code: '1ch', aliases: ['1 Chron'] },
16
+ { name: '2 Chronicles', code: '2ch', aliases: ['2 Chron'] },
17
+ { name: 'Ezra', code: 'ezr', aliases: [] },
18
+ { name: 'Nehemiah', code: 'neh', aliases: ['Neh'] },
19
+ { name: 'Tobit', code: 'tob', aliases: ['Tob'] },
20
+ { name: 'Judith', code: 'jth', aliases: ['Jdt'] },
21
+ { name: 'Esther', code: 'est', aliases: [] },
22
+ { name: 'Job', code: 'job', aliases: [] },
23
+ { name: 'Psalms', code: 'psa', aliases: ['Psalm', 'Ps'] },
24
+ { name: 'Proverbs', code: 'pro', aliases: ['Prov'] },
25
+ { name: 'Ecclesiastes', code: 'ecc', aliases: ['Eccl'] },
26
+ {
27
+ name: 'Song of Songs',
28
+ code: 'son',
29
+ aliases: ['Song of Solomon', 'Canticles'],
30
+ },
31
+ { name: 'Wisdom', code: 'wis', aliases: [] },
32
+ { name: 'Sirach', code: 'sir', aliases: ['Ecclesiasticus'] },
33
+ { name: 'Isaiah', code: 'isa', aliases: ['Isa'] },
34
+ { name: 'Jeremiah', code: 'jer', aliases: ['Jer'] },
35
+ { name: 'Lamentations', code: 'lam', aliases: [] },
36
+ { name: 'Baruch', code: 'bar', aliases: [] },
37
+ { name: 'Ezekiel', code: 'eze', aliases: ['Ezek'] },
38
+ { name: 'Daniel', code: 'dan', aliases: ['Dan'] },
39
+ { name: 'Hosea', code: 'hos', aliases: [] },
40
+ { name: 'Joel', code: 'joe', aliases: [] },
41
+ { name: 'Amos', code: 'amo', aliases: [] },
42
+ { name: 'Obadiah', code: 'oba', aliases: [] },
43
+ { name: 'Jonah', code: 'jon', aliases: [] },
44
+ { name: 'Micah', code: 'mic', aliases: [] },
45
+ { name: 'Nahum', code: 'nah', aliases: [] },
46
+ { name: 'Habakkuk', code: 'hab', aliases: [] },
47
+ { name: 'Zephaniah', code: 'zep', aliases: [] },
48
+ { name: 'Haggai', code: 'hag', aliases: [] },
49
+ { name: 'Zechariah', code: 'zec', aliases: [] },
50
+ { name: 'Malachi', code: 'mal', aliases: [] },
51
+ { name: '1 Maccabees', code: '1ma', aliases: [] },
52
+ { name: '2 Maccabees', code: '2ma', aliases: [] },
53
+ { name: 'Matthew', code: 'mat', aliases: ['Mt', 'Matt'] },
54
+ { name: 'Mark', code: 'mar', aliases: ['Mk'] },
55
+ { name: 'Luke', code: 'luk', aliases: ['Lk'] },
56
+ { name: 'John', code: 'joh', aliases: ['Jn'] },
57
+ { name: 'Acts', code: 'act', aliases: [] },
58
+ { name: 'Romans', code: 'rom', aliases: ['Rom'] },
59
+ { name: '1 Corinthians', code: '1co', aliases: ['1 Cor'] },
60
+ { name: '2 Corinthians', code: '2co', aliases: ['2 Cor'] },
61
+ { name: 'Galatians', code: 'gal', aliases: ['Gal'] },
62
+ { name: 'Ephesians', code: 'eph', aliases: ['Eph'] },
63
+ { name: 'Philippians', code: 'phi', aliases: ['Phil'] },
64
+ { name: 'Colossians', code: 'col', aliases: [] },
65
+ { name: '1 Thessalonians', code: '1th', aliases: ['1 Thess'] },
66
+ { name: '2 Thessalonians', code: '2th', aliases: ['2 Thess'] },
67
+ { name: '1 Timothy', code: '1ti', aliases: ['1 Tim'] },
68
+ { name: '2 Timothy', code: '2ti', aliases: ['2 Tim'] },
69
+ { name: 'Titus', code: 'tit', aliases: [] },
70
+ { name: 'Philemon', code: 'phm', aliases: ['Philem'] },
71
+ { name: 'Hebrews', code: 'heb', aliases: [] },
72
+ { name: 'James', code: 'jam', aliases: ['Jas'] },
73
+ { name: '1 Peter', code: '1pe', aliases: ['1 Pet'] },
74
+ { name: '2 Peter', code: '2pe', aliases: ['2 Pet'] },
75
+ { name: '1 John', code: '1jo', aliases: ['1 Jn'] },
76
+ { name: '2 John', code: '2jo', aliases: ['2 Jn'] },
77
+ { name: '3 John', code: '3jo', aliases: ['3 Jn'] },
78
+ { name: 'Jude', code: 'jud', aliases: [] },
79
+ { name: 'Revelation', code: 'rev', aliases: ['Apocalypse'] },
80
+ ];
@@ -0,0 +1,18 @@
1
+ import { type ScriptureBookCode } from './books.js';
2
+ import type { ScriptureReference } from './references.js';
3
+ export type AmbryScriptureConfig = {
4
+ apiKey: string;
5
+ baseUrl?: string;
6
+ };
7
+ export type ScriptureVerse = {
8
+ book_code: ScriptureBookCode;
9
+ chapter: number;
10
+ verse: number;
11
+ english_text?: string | null;
12
+ greek_text?: string | null;
13
+ latin_text?: string | null;
14
+ };
15
+ export declare function fetchScripture(reference: ScriptureReference, config: AmbryScriptureConfig, fetcher?: typeof fetch): Promise<{
16
+ verses: ScriptureVerse[];
17
+ total: number;
18
+ }>;
@@ -0,0 +1,95 @@
1
+ import { scriptureBooks } from './books.js';
2
+ function validateReference(reference) {
3
+ if (!scriptureBooks.some((book) => book.code === reference.bookCode) ||
4
+ !Number.isInteger(reference.chapter) ||
5
+ reference.chapter < 1 ||
6
+ reference.chapter > 150) {
7
+ throw new Error('Enter a valid scripture book code and chapter.');
8
+ }
9
+ if (reference.firstVerse == null && reference.lastVerse == null)
10
+ return;
11
+ if (!Number.isInteger(reference.firstVerse) ||
12
+ !Number.isInteger(reference.lastVerse) ||
13
+ reference.firstVerse < 1 ||
14
+ reference.lastVerse > 176 ||
15
+ reference.lastVerse < reference.firstVerse) {
16
+ throw new Error('Enter a valid scripture verse or range.');
17
+ }
18
+ }
19
+ export async function fetchScripture(reference, config, fetcher = fetch) {
20
+ validateReference(reference);
21
+ if (typeof config.apiKey !== 'string' || !config.apiKey.trim())
22
+ throw new Error('An Ambry API key is required.');
23
+ const baseUrl = new URL(config.baseUrl ?? 'https://api.ambry.church');
24
+ if (!['https:', 'http:'].includes(baseUrl.protocol) || baseUrl.username || baseUrl.password) {
25
+ throw new Error('Use an HTTP(S) Ambry base URL without embedded credentials.');
26
+ }
27
+ const verses = [];
28
+ let total = 0;
29
+ for (let page = 1; page <= 2; page++) {
30
+ const url = new URL('api/v1/bible-verses', baseUrl.href.replace(/\/?$/, '/'));
31
+ url.searchParams.set('book_code', reference.bookCode);
32
+ url.searchParams.set('chapter', String(reference.chapter));
33
+ if (reference.firstVerse === reference.lastVerse && reference.firstVerse != null)
34
+ url.searchParams.set('verse', String(reference.firstVerse));
35
+ url.searchParams.set('per_page', '100');
36
+ url.searchParams.set('page', String(page));
37
+ const response = await fetcher(url, {
38
+ headers: {
39
+ Authorization: `Bearer ${config.apiKey}`,
40
+ Accept: 'application/json',
41
+ },
42
+ signal: AbortSignal.timeout(15000),
43
+ redirect: 'error',
44
+ });
45
+ if (!response.ok)
46
+ throw new Error(`Ambry scripture request failed (HTTP ${response.status}).`);
47
+ const data = await response.json();
48
+ const result = data;
49
+ if (!result ||
50
+ !result.pagination ||
51
+ result.pagination.page !== page ||
52
+ result.pagination.per_page !== 100 ||
53
+ !Number.isInteger(result.pagination.total) ||
54
+ result.pagination.total < 0 ||
55
+ result.pagination.total > 176 ||
56
+ !Number.isInteger(result.pagination.total_pages) ||
57
+ result.pagination.total_pages < 0 ||
58
+ result.pagination.total_pages > 2 ||
59
+ (result.data != null && !Array.isArray(result.data))) {
60
+ throw new Error('Ambry returned an invalid scripture response.');
61
+ }
62
+ total = result.pagination.total;
63
+ for (const verse of result.data ?? []) {
64
+ if (!verse ||
65
+ verse.book_code !== reference.bookCode ||
66
+ verse.chapter !== reference.chapter ||
67
+ !Number.isInteger(verse.verse) ||
68
+ verse.verse < 1 ||
69
+ verse.verse > 176 ||
70
+ ['english_text', 'greek_text', 'latin_text'].some((field) => verse[field] != null && typeof verse[field] !== 'string') ||
71
+ (reference.firstVerse === reference.lastVerse &&
72
+ reference.firstVerse != null &&
73
+ verse.verse !== reference.firstVerse)) {
74
+ throw new Error('Ambry returned an invalid scripture verse.');
75
+ }
76
+ if (verses.some((saved) => saved.verse === verse.verse))
77
+ throw new Error('Ambry returned duplicate scripture verses.');
78
+ verses.push(verse);
79
+ }
80
+ if (page >= result.pagination.total_pages)
81
+ break;
82
+ }
83
+ if (verses.length !== total)
84
+ throw new Error('Ambry returned an incomplete scripture passage.');
85
+ const selected = verses
86
+ .sort((a, b) => a.verse - b.verse)
87
+ .filter((verse) => reference.firstVerse == null ||
88
+ (verse.verse >= reference.firstVerse && verse.verse <= reference.lastVerse));
89
+ if (reference.firstVerse != null &&
90
+ selected.length &&
91
+ selected.length !== reference.lastVerse - reference.firstVerse + 1) {
92
+ throw new Error('Ambry did not return every verse in the requested range.');
93
+ }
94
+ return { verses: selected, total: selected.length };
95
+ }
@@ -0,0 +1,2 @@
1
+ export { scriptureBooks, type ScriptureBook, type ScriptureBookCode } from './books.js';
2
+ export { parseScriptureReference, findScriptureReferences, scriptureLanguages, type ScriptureLanguage, type ScriptureReference, type ParseScriptureOptions, type FindScriptureOptions, } from './references.js';
@@ -0,0 +1,2 @@
1
+ export { scriptureBooks } from './books.js';
2
+ export { parseScriptureReference, findScriptureReferences, scriptureLanguages, } from './references.js';
@@ -0,0 +1,32 @@
1
+ import { type ScriptureBookCode } from './books.js';
2
+ export type ScriptureLanguage = 'english' | 'greek' | 'latin';
3
+ export type ScriptureReference = {
4
+ book: string;
5
+ bookCode: ScriptureBookCode;
6
+ chapter: number;
7
+ firstVerse?: number;
8
+ lastVerse?: number;
9
+ language?: ScriptureLanguage;
10
+ };
11
+ export type ParseScriptureOptions = {
12
+ maxVerses?: number;
13
+ };
14
+ export type FindScriptureOptions = ParseScriptureOptions & {
15
+ maxReferences?: number;
16
+ };
17
+ export declare const scriptureLanguages: {
18
+ readonly english: {
19
+ readonly label: "English";
20
+ readonly field: "english_text";
21
+ };
22
+ readonly greek: {
23
+ readonly label: "Greek";
24
+ readonly field: "greek_text";
25
+ };
26
+ readonly latin: {
27
+ readonly label: "Latin";
28
+ readonly field: "latin_text";
29
+ };
30
+ };
31
+ export declare function parseScriptureReference(input: string, options?: ParseScriptureOptions): ScriptureReference | undefined;
32
+ export declare function findScriptureReferences(content: string, options?: FindScriptureOptions): ScriptureReference[];