@faith-tools/bible-sdk 0.0.0-stage → 0.7.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,431 @@
1
+ import { a as e, c as t, d as n, f as r, i, l as a, n as o, o as s, r as c, s as l, u, v as d } from "./runtime-CVlBLU4v.js";
2
+ import { Effect as f, Schema as p } from "effect";
3
+ import { FreeUseBibleApi as m } from "free-use-bible-api";
4
+ // src/providers.ts
5
+ var h = {}, g = o(p.Struct({ books: p.Array(p.Struct({
6
+ id: p.NonEmptyString,
7
+ name: p.String,
8
+ firstChapterNumber: p.Int.check(p.isGreaterThan(0)),
9
+ lastChapterNumber: p.Int.check(p.isGreaterThan(0))
10
+ }).check(p.makeFilter((e) => e.lastChapterNumber >= e.firstChapterNumber))) })), _ = p.Struct({
11
+ id: p.NonEmptyString,
12
+ name: p.String,
13
+ language: e,
14
+ shortName: p.optional(p.String),
15
+ languageName: p.optional(p.String),
16
+ languageEnglishName: p.optional(p.String)
17
+ }), v = p.Array(p.Union([
18
+ p.Struct({
19
+ type: p.Literal("verse"),
20
+ number: p.Int,
21
+ content: p.Array(p.Union([
22
+ p.String,
23
+ p.Struct({
24
+ text: p.String,
25
+ poem: p.optional(p.Number),
26
+ wordsOfJesus: p.optional(p.Boolean)
27
+ }),
28
+ p.Struct({ noteId: p.Number }),
29
+ p.Struct({ heading: p.String }),
30
+ p.Struct({ lineBreak: p.Literal(!0) })
31
+ ]))
32
+ }),
33
+ p.Struct({
34
+ type: p.Literals(["heading", "hebrew_subtitle"]),
35
+ content: p.Array(p.Union([
36
+ p.String,
37
+ p.Struct({ text: p.String }),
38
+ p.Struct({ noteId: p.Number })
39
+ ]))
40
+ }),
41
+ p.Struct({ type: p.Literal("line_break") })
42
+ ])), y = o(p.Struct({
43
+ translation: p.Struct({
44
+ id: p.NonEmptyString,
45
+ name: p.String,
46
+ licenseUrl: p.String,
47
+ language: e,
48
+ shortName: p.optional(p.String),
49
+ textDirection: p.optional(p.Literals(["ltr", "rtl"])),
50
+ licenseNotice: p.optional(p.NullOr(p.String)),
51
+ licenseNotes: p.optional(p.NullOr(p.String)),
52
+ license: p.optional(p.NullOr(p.Record(p.String, p.Union([p.Boolean, p.String]))))
53
+ }),
54
+ book: p.Struct({ name: p.String }),
55
+ chapter: p.Struct({ content: v })
56
+ })), b = (e) => o(p.Struct({ data: p.Array(e) }));
57
+ function x(e) {
58
+ return {
59
+ text: `${e.licenseNotice || `${e.name}. ${e.licenseUrl}`} · Source: HelloAO Free Use Bible API`,
60
+ html: `${e.licenseNotice ? t(e.licenseNotice) : `${s(e.name, e.licenseUrl)}.`} · Source: ${s("HelloAO Free Use Bible API", "https://bible.helloao.org/docs/")}`
61
+ };
62
+ }
63
+ function S(e, n) {
64
+ let r = n === void 0 ? "" : `<sup class="scripture-verse-number">${n}</sup> `;
65
+ return e.map((e) => {
66
+ if (typeof e == "string" || "text" in e) {
67
+ let n = r;
68
+ if (r = "", typeof e == "string") return n + t(e);
69
+ let i = t(e.text), a = e.wordsOfJesus ? `<span class="scripture-jesus">${i}</span>` : i;
70
+ return e.poem === void 0 ? n + a : `<span class="scripture-poetry" style="--indent:${e.poem}">${n}${a}</span>`;
71
+ }
72
+ return "heading" in e ? `<span class="scripture-heading">${t(e.heading)}</span>` : "lineBreak" in e ? "<br>" : " ";
73
+ }).join("");
74
+ }
75
+ function C() {
76
+ let e = new m({ useCache: !1 }), s = u(), h = (t) => s.get(JSON.stringify(["books", t]), () => c("helloao.books", (n) => e.getTranslationBooks(t, void 0, { signal: n })).pipe(f.flatMap(g))), v = (t, n, r) => s.get(JSON.stringify([
77
+ "chapter",
78
+ t,
79
+ n,
80
+ r
81
+ ]), () => c("helloao.chapter", (i) => e.getTranslationBookChapter(t, n, r, void 0, { signal: i })).pipe(f.flatMap(y))), b = {
82
+ id: "helloao",
83
+ defaultVersionId: "BSB",
84
+ clearCache: s.clear,
85
+ listBooks: f.fn("helloao.listBooks")(function* (e) {
86
+ return (yield* h(e)).books.map((e) => ({
87
+ id: e.id,
88
+ title: e.name
89
+ }));
90
+ }),
91
+ listChapters: f.fn("helloao.listChapters")(function* (e, t) {
92
+ yield* l(t);
93
+ let n = (yield* h(e)).books.find((e) => e.id === t);
94
+ return n ? Array.from({ length: n.lastChapterNumber - n.firstChapterNumber + 1 }, (e, r) => {
95
+ let i = n.firstChapterNumber + r;
96
+ return {
97
+ number: i,
98
+ passageId: `${t}.${i}`
99
+ };
100
+ }) : yield* new d({
101
+ code: "unavailable",
102
+ message: "Book is not available in this version."
103
+ });
104
+ }),
105
+ getPassageData: f.fn("helloao.getPassageData")(function* (t, i) {
106
+ let { book: o, chapter: s, first: c, last: l } = yield* a(i), u = yield* v(t, o, s), d = u.chapter.content.filter((e) => e.type === "verse");
107
+ yield* r(d.map((e) => e.number), c, l);
108
+ let f = "", p = !1;
109
+ for (let e of u.chapter.content) if (e.type === "verse") {
110
+ if (p = c === void 0 || e.number >= c && e.number <= l, !p) continue;
111
+ f && !/\s$/.test(f) && (f += " ");
112
+ let t;
113
+ for (let [n, r] of e.content.entries()) {
114
+ if (typeof r == "string" || "text" in r) {
115
+ let i = typeof r == "string" ? void 0 : r.poem, a = e.content[n - 1], o = a !== void 0 && typeof a != "string" && "noteId" in a && t !== void 0 && i === t;
116
+ t === void 0 && i === void 0 || o || !f || f.endsWith("\n") || (f = f.trimEnd() + "\n"), t = i;
117
+ }
118
+ if (typeof r == "string") f += r;
119
+ else if ("text" in r) f += r.text;
120
+ else if ("lineBreak" in r) f = f.trimEnd() + "\n";
121
+ else if ("noteId" in r) {
122
+ let t = e.content.slice(n + 1).find((e) => typeof e == "string" || "text" in e), r = typeof t == "string" ? t : t && "text" in t ? t.text : "";
123
+ f && !/\s$/.test(f) && r && !/^[\s,.;:!?…\)\]”’]/.test(r) && (f += " ");
124
+ }
125
+ }
126
+ } else e.type === "hebrew_subtitle" && (c === void 0 || c === 1) ? f += e.content.map((e) => typeof e == "string" ? e : "text" in e ? e.text : "lineBreak" in e ? "\n" : "").join("") + "\n\n" : e.type === "line_break" && p && (f = f.trimEnd() + "\n\n");
127
+ let m = u.translation;
128
+ return {
129
+ provider: "helloao",
130
+ source: {
131
+ url: `${e.endpoint.replace(/\/$/, "")}/api/${encodeURIComponent(t)}/${o}/${s}.json`,
132
+ versionId: t
133
+ },
134
+ requestedPassageId: i,
135
+ passageId: i,
136
+ reference: `${u.book.name} ${s}${c === void 0 ? "" : `:${c}${l === c ? "" : `-${l}`}`}`,
137
+ text: f.trim(),
138
+ version: {
139
+ id: m.id,
140
+ title: m.name,
141
+ abbreviation: m.shortName || m.id,
142
+ language: new Intl.Locale(m.language).language,
143
+ sourceLanguage: m.language
144
+ },
145
+ attribution: {
146
+ text: x(m).text,
147
+ urls: [m.licenseUrl, "https://bible.helloao.org/docs/"].filter(Boolean)
148
+ },
149
+ licenses: m.licenseUrl || m.license ? [{
150
+ url: m.licenseUrl,
151
+ ...m.license ? { restrictions: { ...m.license } } : {}
152
+ }] : [],
153
+ numbering: "unknown",
154
+ display: {
155
+ format: "text",
156
+ whitespace: "pre-wrap",
157
+ attributionPlacement: "after-passage",
158
+ direction: m.textDirection,
159
+ language: m.language
160
+ },
161
+ instructions: [...n(), ...m.licenseNotes ? [{
162
+ code: "translation-license-notes",
163
+ level: "notice",
164
+ appliesTo: "all",
165
+ text: m.licenseNotes
166
+ }] : []]
167
+ };
168
+ }),
169
+ listVersions: f.fn("helloao.listVersions")(function* () {
170
+ let { translations: t } = yield* s.get("translations", () => c("helloao.translations", (t) => e.getAvailableTranslations(void 0, { signal: t })).pipe(f.tap(o(p.Struct({ translations: p.Array(_) })))));
171
+ return t.map((e) => ({
172
+ id: e.id,
173
+ abbreviation: e.shortName || e.id,
174
+ title: e.name,
175
+ language: new Intl.Locale(e.language).language,
176
+ languageName: e.languageEnglishName || e.languageName || e.language
177
+ }));
178
+ }),
179
+ getPassageDisplay: f.fn("helloao.getPassageDisplay")(function* (e, n) {
180
+ let i = yield* a(n), o = yield* v(e, i.book, i.chapter), s = o.chapter.content.filter((e) => e.type === "verse");
181
+ yield* r(s.map((e) => e.number), i.first, i.last);
182
+ let c = Math.max(...s.map((e) => e.number)), l = i.first ?? 1, u = i.last ?? c, d = "", f = "", p = !1;
183
+ for (let e of o.chapter.content) e.type === "heading" ? d += `<h3 class="scripture-heading">${t(e.content.join(" "))}</h3>` : e.type === "verse" ? (p = e.number >= l && e.number <= u, p && (f += `${d}<span class="scripture-verse">${S(e.content, e.number)}</span> `), d = "") : e.type === "hebrew_subtitle" && l === 1 ? f += `<p class="scripture-subtitle">${S(e.content)}</p>` : e.type === "line_break" && p && (f += "<br>");
184
+ let m = o.translation, h = x(m);
185
+ return {
186
+ html: f,
187
+ version: {
188
+ id: m.id,
189
+ abbreviation: m.shortName || m.id,
190
+ title: m.name
191
+ },
192
+ attribution: h.text,
193
+ attributionHtml: h.html,
194
+ direction: m.textDirection,
195
+ containerAttributes: {
196
+ class: "scripture-bible",
197
+ lang: m.language
198
+ }
199
+ };
200
+ })
201
+ };
202
+ return i(b);
203
+ }
204
+ var w = C();
205
+ function T({ yvpPublicAppKey: u, yvpApiHost: m }) {
206
+ let h = p.String.check(p.isPattern(/^[1-9]\d*$/), p.makeFilter((e) => Number.isSafeInteger(Number(e)) || "Use a safe integer version ID.")), g = f.fnUntraced(function* (e) {
207
+ if (!u) return yield* new d({
208
+ code: "authentication",
209
+ message: "The YouVersion provider needs a public app key."
210
+ });
211
+ e !== void 0 && (yield* p.decodeUnknownEffect(h)(e).pipe(f.mapError((e) => new d({
212
+ code: "unavailable",
213
+ message: "Set a positive YouVersion Bible version ID.",
214
+ cause: e
215
+ }))));
216
+ let t = yield* c("youversion.loadSdk", () => import("@youversion/platform-core"));
217
+ return {
218
+ sdk: t,
219
+ client: new t.ApiClient({
220
+ appKey: u,
221
+ apiHost: m
222
+ })
223
+ };
224
+ }), _ = {
225
+ id: "youversion",
226
+ defaultVersionId: "3034",
227
+ clearCache: f.void,
228
+ listBooks: f.fn("youversion.listBooks")(function* (e) {
229
+ let { sdk: t, client: n } = yield* g(e);
230
+ return (yield* c("youversion.books", () => t.getBooks(n, Number(e))).pipe(f.tap(b(p.Struct({
231
+ id: p.String,
232
+ title: p.String
233
+ }))))).data.map((e) => ({
234
+ id: e.id,
235
+ title: e.title
236
+ }));
237
+ }),
238
+ listChapters: f.fn("youversion.listChapters")(function* (e, t) {
239
+ yield* l(t);
240
+ let { sdk: n, client: r } = yield* g(e);
241
+ return (yield* c("youversion.chapters", () => n.getChapters(r, Number(e), t)).pipe(f.tap(b(p.Struct({
242
+ id: p.String,
243
+ passage_id: p.String
244
+ }))))).data.map((e) => ({
245
+ number: Number(e.id),
246
+ passageId: e.passage_id
247
+ }));
248
+ }),
249
+ getPassageData: f.fn("youversion.getPassageData")(function* (t, i) {
250
+ let { book: s, chapter: l, first: h, last: _ } = yield* a(i), { sdk: v, client: y } = yield* g(t), x = yield* c("youversion.verses", () => v.getVerses(y, Number(t), s, l)).pipe(f.tap(b(p.Struct({ id: p.String }))));
251
+ yield* r(x.data.map((e) => Number(e.id)), h, _);
252
+ let [S, C] = yield* f.all([c("youversion.text", () => v.getPassage(y, Number(t), i, "text", !1, !1)).pipe(f.tap(o(p.Struct({
253
+ id: p.String,
254
+ reference: p.String,
255
+ content: p.String
256
+ })))), c("youversion.version", () => v.getVersion(y, Number(t))).pipe(f.tap(o(p.Struct({
257
+ id: p.Number,
258
+ localized_title: p.String,
259
+ localized_abbreviation: p.String,
260
+ language_tag: e,
261
+ copyright: p.optional(p.NullOr(p.String)),
262
+ promotional_content: p.optional(p.NullOr(p.String)),
263
+ publisher_url: p.optional(p.NullOr(p.String))
264
+ }))))], { concurrency: 2 }), w = v.getPassageAttribution(C);
265
+ return w ? {
266
+ provider: "youversion",
267
+ source: {
268
+ url: `https://${m || "api.youversion.com"}/v1`,
269
+ versionId: t
270
+ },
271
+ requestedPassageId: i,
272
+ passageId: S.id,
273
+ reference: S.reference,
274
+ text: S.content,
275
+ version: {
276
+ id: String(C.id),
277
+ title: C.localized_title,
278
+ abbreviation: C.localized_abbreviation,
279
+ language: C.language_tag,
280
+ sourceLanguage: C.language_tag
281
+ },
282
+ attribution: {
283
+ text: `${w.text} · Source: YouVersion Platform`,
284
+ urls: [C.publisher_url, "https://developers.youversion.com/"].filter((e) => !!e)
285
+ },
286
+ licenses: [],
287
+ numbering: "unknown",
288
+ display: {
289
+ format: "text",
290
+ whitespace: "pre-wrap",
291
+ attributionPlacement: "after-passage",
292
+ language: C.language_tag,
293
+ nativeHtml: {
294
+ containerAttributes: v.BIBLE_CONTAINER_ATTRIBUTES,
295
+ stylesheets: v.getBibleStylesheets({
296
+ appKey: u,
297
+ apiHost: m
298
+ })
299
+ }
300
+ },
301
+ instructions: [
302
+ ...n(),
303
+ {
304
+ code: "youversion-commercial-use",
305
+ level: "required",
306
+ appliesTo: "all",
307
+ text: "YouVersion has no commercial-use flag. Its Platform terms do not grant Bible-content rights: confirm the selected publisher's license and applicable Tool terms before commercial use. Paid applications must conspicuously state that the YouVersion Bible App is free. fetch.bible usage settings do not apply to YouVersion.",
308
+ urls: ["https://platform.youversion.com/terms"]
309
+ },
310
+ {
311
+ code: "youversion-ai-use",
312
+ level: "required",
313
+ appliesTo: "all",
314
+ text: "YouVersion prohibits using its Tools with AI for open-ended user chat, except to retrieve and display Scripture verbatim, word-for-word and unaltered. Do not use the Tools to train, develop, refine, or improve AI. Cases beyond the expressly permitted uses require prior written YouVersion approval. The terms separately permit AI-assisted engineering and content generation subject to their stated conditions; review the full terms.",
315
+ urls: ["https://platform.youversion.com/terms"]
316
+ },
317
+ {
318
+ code: "youversion-terms",
319
+ level: "required",
320
+ appliesTo: "all",
321
+ text: "Follow your YouVersion account and content agreements. This SDK does not establish persistent caching or offline rights. Attribution is refreshed on every data request.",
322
+ urls: ["https://developers.youversion.com/sdks/javascript/guides/copyright-and-attribution"]
323
+ },
324
+ {
325
+ code: "youversion-native-html",
326
+ level: "required",
327
+ appliesTo: "html",
328
+ text: "If you request native HTML through the display provider, apply its returned containerAttributes and stylesheets. Load Untitled Serif from the YouVersion Fonts API; do not download or self-host its font files. These HTML resources are not required to interpret the plain-text result.",
329
+ urls: ["https://developers.youversion.com/guides/display-bible-html"]
330
+ }
331
+ ]
332
+ } : yield* new d({
333
+ code: "unavailable",
334
+ message: "This Bible version has no display attribution."
335
+ });
336
+ }),
337
+ listVersions: f.fn("youversion.listVersions")(function* () {
338
+ let { sdk: { getVersions: t }, client: n } = yield* g(), r = new Intl.DisplayNames(["en"], { type: "language" }), i = [], a = /* @__PURE__ */ new Set(), o = null;
339
+ do {
340
+ let s = yield* c("youversion.versions", () => t(n, "*", void 0, {
341
+ page_size: 99,
342
+ page_token: o || void 0,
343
+ fields: [
344
+ "id",
345
+ "localized_abbreviation",
346
+ "localized_title",
347
+ "language_tag"
348
+ ]
349
+ })).pipe(f.tap(b(p.Struct({
350
+ id: p.Number,
351
+ localized_abbreviation: p.String,
352
+ localized_title: p.String,
353
+ language_tag: e
354
+ }))));
355
+ if (i.push(...s.data.map((e) => ({
356
+ id: String(e.id),
357
+ abbreviation: e.localized_abbreviation,
358
+ title: e.localized_title,
359
+ language: e.language_tag,
360
+ languageName: r.of(e.language_tag)
361
+ }))), o = s.next_page_token, o && a.has(o)) return yield* new d({
362
+ code: "invalid_response",
363
+ message: "Bible provider repeated a catalog page token."
364
+ });
365
+ o && a.add(o);
366
+ } while (o);
367
+ return i;
368
+ }),
369
+ getPassageDisplay: f.fn("youversion.getPassageDisplay")(function* (e, n) {
370
+ yield* a(n);
371
+ let { sdk: { getPassageDisplay: r }, client: i } = yield* g(e), o = yield* c("youversion.html", () => r(i, {
372
+ versionId: Number(e),
373
+ passageId: n,
374
+ includeHeadings: !0,
375
+ includeNotes: !1
376
+ }));
377
+ return {
378
+ ...o,
379
+ version: {
380
+ id: String(o.version.id),
381
+ abbreviation: o.version.localized_abbreviation,
382
+ title: o.version.localized_title
383
+ },
384
+ attribution: `${o.attribution.text} · Source: YouVersion Platform`,
385
+ attributionHtml: `${t(o.attribution.text)} · Source: ${s("YouVersion Platform", "https://developers.youversion.com/")}`,
386
+ yvpBibleVersion: o.version
387
+ };
388
+ })
389
+ };
390
+ return i(_);
391
+ }
392
+ var E = /* @__PURE__ */ new Map();
393
+ function D(e) {
394
+ if (typeof e.provider == "object") return e.provider;
395
+ if (!e.provider || e.provider === "helloao") return w;
396
+ if (e.provider !== "youversion") throw new d({
397
+ code: "unsupported",
398
+ message: `Unknown Bible provider: ${e.provider}`
399
+ });
400
+ let t = JSON.stringify([e.yvpPublicAppKey, e.yvpApiHost]), n = E.get(t);
401
+ return n || (n = T(e), E.set(t, n)), n;
402
+ }
403
+ var O = (e) => f.try({
404
+ try: () => D(e),
405
+ catch: (e) => e instanceof d ? e : new d({
406
+ code: "unsupported",
407
+ message: "Invalid Bible provider configuration.",
408
+ cause: e
409
+ })
410
+ }), k = /* @__PURE__ */ new WeakMap(), A = f.fn("scripture.listBibleVersions")(function* (e = {}) {
411
+ let t = yield* O({
412
+ ...h,
413
+ ...e
414
+ });
415
+ if (!t.listVersions) return yield* new d({
416
+ code: "unsupported",
417
+ message: "This Bible provider does not support listing versions."
418
+ });
419
+ let n = k.get(t);
420
+ return n || k.set(t, n = u()), yield* n.get("versions", () => t.effects?.listVersions() ?? c("custom.listVersions", () => t.listVersions(), !1));
421
+ });
422
+ function j(e = {}) {
423
+ return f.runPromise(A(e));
424
+ }
425
+ var M = /* @__PURE__ */ new WeakMap(), N = f.fn("scripture.fetchDisplay")(function* (e, t, n) {
426
+ let r = M.get(e);
427
+ r || M.set(e, r = u());
428
+ let i = JSON.stringify([t, n]);
429
+ return yield* r.get(i, () => e.effects?.getPassageDisplay(t, n) ?? c("custom.getPassage", () => e.getPassage(t, n), !1));
430
+ });
431
+ export { j as a, D as c, w as i, O as l, T as n, A as o, N as r, h as s, C as t };
@@ -0,0 +1,229 @@
1
+ import { Cache as e, Context as t, Duration as n, Effect as r, Exit as i, Schedule as a, Schema as o } from "effect";
2
+ // src/data-types.ts
3
+ var s = o.Struct({
4
+ id: o.NonEmptyString,
5
+ abbreviation: o.String,
6
+ title: o.String,
7
+ language: o.optional(o.String),
8
+ languageName: o.optional(o.String)
9
+ }), c = o.Struct({
10
+ code: o.NonEmptyString,
11
+ level: o.Literals([
12
+ "required",
13
+ "recommended",
14
+ "notice"
15
+ ]),
16
+ appliesTo: o.Literals([
17
+ "all",
18
+ "text",
19
+ "html"
20
+ ]),
21
+ text: o.NonEmptyString,
22
+ urls: o.optional(o.Array(o.String))
23
+ }), l = o.Struct({
24
+ id: o.NonEmptyString,
25
+ title: o.String
26
+ }), u = o.Struct({
27
+ passageId: o.NonEmptyString,
28
+ number: o.Int.check(o.isGreaterThan(0))
29
+ }), d = o.Struct({
30
+ provider: o.NonEmptyString,
31
+ source: o.Struct({
32
+ url: o.String,
33
+ versionId: o.NonEmptyString
34
+ }),
35
+ requestedPassageId: o.NonEmptyString,
36
+ passageId: o.NonEmptyString,
37
+ reference: o.String,
38
+ text: o.String,
39
+ version: s.mapFields((e) => ({
40
+ ...e,
41
+ sourceLanguage: o.optional(o.String)
42
+ })),
43
+ attribution: o.Struct({
44
+ text: o.NonEmptyString,
45
+ urls: o.Array(o.String)
46
+ }),
47
+ publisher: o.optional(o.Struct({
48
+ copyrightHtml: o.String,
49
+ infoHtml: o.String
50
+ })),
51
+ reporting: o.optional(o.Struct({
52
+ kind: o.Literal("api-bible-fums"),
53
+ token: o.NonEmptyString
54
+ })),
55
+ cache: o.optional(o.Struct({ expiresAt: o.Number })),
56
+ licenses: o.Array(o.Struct({
57
+ name: o.optional(o.String),
58
+ url: o.String,
59
+ restrictions: o.optional(o.Record(o.String, o.Union([o.Boolean, o.String])))
60
+ })),
61
+ numbering: o.Literals(["kjv", "unknown"]),
62
+ sourceLimitations: o.optional(o.Array(o.Struct({
63
+ kind: o.Literal("source-trimming"),
64
+ startPassageId: o.NonEmptyString,
65
+ endPassageId: o.NonEmptyString,
66
+ appliesToRequest: o.Boolean
67
+ }))),
68
+ display: o.Struct({
69
+ format: o.Literal("text"),
70
+ whitespace: o.Literal("pre-wrap"),
71
+ attributionPlacement: o.Literal("after-passage"),
72
+ direction: o.optional(o.Literals(["ltr", "rtl"])),
73
+ language: o.optional(o.String),
74
+ nativeHtml: o.optional(o.Struct({
75
+ containerAttributes: o.Record(o.String, o.String),
76
+ stylesheets: o.Array(o.Struct({
77
+ kind: o.Literals(["bible", "font"]),
78
+ href: o.String
79
+ }))
80
+ }))
81
+ }),
82
+ instructions: o.Array(c)
83
+ }), f = class extends t.Service()("@faith-tools/scripture-inline/data/BibleSource") {}, p = o.Literals([
84
+ "invalid_reference",
85
+ "unavailable",
86
+ "unsupported",
87
+ "authentication",
88
+ "rate_limit",
89
+ "network",
90
+ "timeout",
91
+ "invalid_response"
92
+ ]), m = class extends o.TaggedError()("ScriptureError", {
93
+ code: p,
94
+ message: o.String,
95
+ cause: o.optional(o.Defect())
96
+ }) {
97
+ get retryable() {
98
+ return this.code === "network" || this.code === "rate_limit";
99
+ }
100
+ }, h = o.String.check(o.makeFilter((e) => {
101
+ try {
102
+ return new Intl.Locale(e), !0;
103
+ } catch {
104
+ return "Invalid source language tag.";
105
+ }
106
+ })), g = (e) => e.replace(/[&<>"']/g, (e) => ({
107
+ "&": "&amp;",
108
+ "<": "&lt;",
109
+ ">": "&gt;",
110
+ "\"": "&quot;",
111
+ "'": "&#39;"
112
+ })[e]);
113
+ function _(e, t) {
114
+ let n = g(e);
115
+ return /^https?:\/\//i.test(t) ? `<a href="${g(t)}">${n}</a>` : n;
116
+ }
117
+ var v = o.String.check(o.isPattern(/^[1-4A-Z][A-Z0-9]{2}\.[1-9]\d*(?:\.[1-9]\d*(?:-[1-9]\d*)?)?$/)), y = o.String.check(o.isPattern(/^[1-4A-Z][A-Z0-9]{2}$/)), b = o.NumberFromString.check(o.isInt(), o.isGreaterThan(0), o.isLessThanOrEqualTo(2 ** 53 - 1)), x = o.Struct({
118
+ book: y,
119
+ chapter: b,
120
+ first: o.optional(b),
121
+ last: o.optional(b)
122
+ }).check(o.makeFilter((e) => e.first === void 0 || e.last >= e.first || "Range endpoints must be ascending.")), S = (e) => new m({
123
+ code: "invalid_reference",
124
+ message: "Use an uppercase USFM verse, ascending range, or chapter with positive safe integers. Ranges cannot cross chapters.",
125
+ cause: e
126
+ }), C = r.fnUntraced(function* (e) {
127
+ let [t, n, i] = (yield* o.decodeUnknownEffect(v)(e).pipe(r.mapError(S))).split("."), [a, s = a] = i?.split("-") ?? [];
128
+ return yield* o.decodeUnknownEffect(x)({
129
+ book: t,
130
+ chapter: n,
131
+ first: a,
132
+ last: s
133
+ }).pipe(r.mapError(S));
134
+ }), w = (e) => o.decodeUnknownEffect(y)(e).pipe(r.mapError(S));
135
+ function T(e, t, n) {
136
+ return !e.length || t !== void 0 && (!e.includes(t) || !e.includes(n)) ? r.fail(new m({
137
+ code: "unavailable",
138
+ message: "Passage is not available in this version."
139
+ })) : r.void;
140
+ }
141
+ function E() {
142
+ return [
143
+ {
144
+ code: "display-attribution",
145
+ level: "required",
146
+ appliesTo: "all",
147
+ text: "Display attribution.text after the passage, separately from Scripture. Preserve its wording and supplied source and license links."
148
+ },
149
+ {
150
+ code: "preserve-scripture",
151
+ level: "required",
152
+ appliesTo: "text",
153
+ text: "Render text as text, not HTML. Preserve wording, punctuation, meaningful line and paragraph breaks, and display.direction when supplied. Do not add notes or headings to the Scripture text."
154
+ },
155
+ {
156
+ code: "verify-license",
157
+ level: "required",
158
+ appliesTo: "all",
159
+ text: "Check the selected translation's license and provider terms for your intended use. Missing metadata is not permission for commercial use, redistribution, modifications, or offline storage."
160
+ },
161
+ {
162
+ code: "plain-text-limits",
163
+ level: "notice",
164
+ appliesTo: "text",
165
+ text: "Plain text omits verse numbers, editorial headings, notes, and rich formatting. It is not a lossless representation of the source edition."
166
+ }
167
+ ];
168
+ }
169
+ function D(t = n.infinity) {
170
+ let a = /* @__PURE__ */ new Map(), o = r.runSync(e.makeWith((e) => r.suspend(() => a.get(e)()), {
171
+ capacity: 256,
172
+ requireServicesAt: "lookup",
173
+ timeToLive: (e) => i.isSuccess(e) ? t : n.zero
174
+ }));
175
+ return {
176
+ get(t, n) {
177
+ return r.suspend(() => (a.set(t, n), e.get(o, t).pipe(r.ensuring(r.sync(() => {
178
+ a.get(t) === n && a.delete(t);
179
+ })))));
180
+ },
181
+ clear: e.invalidateAll(o)
182
+ };
183
+ }
184
+ // src/runtime.ts
185
+ var O = (e) => (t) => o.decodeUnknownEffect(e)(t).pipe(r.mapError((e) => new m({
186
+ code: "invalid_response",
187
+ message: "Bible provider returned invalid data.",
188
+ cause: e
189
+ }))), k = t.Reference("@faith-tools/scripture-inline/RequestPolicy", { defaultValue: () => ({
190
+ timeout: "15 seconds",
191
+ retries: 2
192
+ }) }), A = o.Struct({ status: o.Number }), j = o.Struct({ response: A }), M = o.decodeUnknownOption(A), N = o.decodeUnknownOption(j), P = o.decodeUnknownOption(o.Struct({ code: o.String }));
193
+ function F(e) {
194
+ if (e instanceof m) return e;
195
+ let t = M(e), n = N(e), r = P(e), i = t._tag === "Some" ? t.value.status : n._tag === "Some" ? n.value.response.status : Number(e instanceof Error ? /(?:Status: |^)(\d{3})\b/.exec(e.message)?.[1] : void 0), a = r._tag === "Some" && r.value.code === "missing_passage_attribution" ? "unavailable" : e instanceof SyntaxError || e instanceof Error && /^\$?ZodError$/.test(e.name) ? "invalid_response" : i === 401 || i === 403 ? "authentication" : i === 429 ? "rate_limit" : i >= 400 && i < 500 ? "unavailable" : "network";
196
+ return new m({
197
+ code: a,
198
+ message: `Bible provider request failed (${a}).`,
199
+ cause: e
200
+ });
201
+ }
202
+ var I = r.fn("scripture.request")(function* (e, t, n = !0) {
203
+ yield* r.annotateCurrentSpan({ operation: e });
204
+ let i = yield* k;
205
+ return yield* r.tryPromise({
206
+ try: t,
207
+ catch: F
208
+ }).pipe(r.retry({
209
+ times: n ? i.retries : 0,
210
+ schedule: a.exponential("100 millis"),
211
+ while: (e) => e.retryable
212
+ }), r.timeoutOrElse({
213
+ duration: i.timeout,
214
+ orElse: () => r.fail(new m({
215
+ code: "timeout",
216
+ message: "Bible provider request timed out."
217
+ }))
218
+ }));
219
+ });
220
+ function L(e) {
221
+ return {
222
+ id: e.id,
223
+ defaultVersionId: e.defaultVersionId,
224
+ effects: e,
225
+ listVersions: () => r.runPromise(e.listVersions()),
226
+ getPassage: (t, n) => r.runPromise(e.getPassageDisplay(t, n))
227
+ };
228
+ }
229
+ export { c as _, h as a, d as b, g as c, E as d, T as f, s as g, f as h, L as i, C as l, u as m, O as n, _ as o, l as p, I as r, w as s, k as t, D as u, m as v, p as y };