Releases: midvash/emdash-plugin-bible
v0.4.0
Minor Changes
-
#57
5780453Thanks @onetogregorio! - The version badge (e.g. "NAA", "NIV", "ACF") in the tooltip header is now a
real<a href>pointing at the version's index page on midvash.com
(https://midvash.com/{language}/{version}). Another in-document SEO link
distinct from the article-body anchor — passes additional link equity to the
version's slug page.Same SEO contract as the verse anchor:
- ✅ no
rel="nofollow"— juice passes - ✅ no
target="_blank"— in-document, crawlers preferred - ✅
title="<VERSION> on Midvash"for crawler context - ✅
rel="noopener"only (window-opener guard)
Visual: the badge keeps its pill styling — link underline is suppressed and a
subtle brightness shift on hover/focus signals it's clickable. When the
upstream returns an emptyversion, the badge falls back to a non-linked
<span>(or is hidden entirely whenshowVersionBadgeis off).If you target the badge via CSS, the selector remains
.midvash-tooltip__badge. Selectors targetingspan.midvash-tooltip__badge
specifically should switch to the class-only form. - ✅ no
v0.3.1
Patch Changes
-
#55
41e6629Thanks @onetogregorio! - 🚨 Hotfix: client bundle threw SyntaxError on every page (silently), so 0
references got linkified and 0 tooltips ever rendered. Confirmed against two
production sites running v0.3.0.Cause: Astro/EmDash escape every literal
</inside<script>content to
<\/before shipping the HTML (standard XSS hardening so a stray
</script>can't break out of the inline script). That rewrite silently
corruptedescapeHtml's/</gregex literal —/<\/gparses as/<
(regex) +\/g(something else) and throws "Invalid regular expression:
missing /" the moment the IIFE evaluates. The error happened so early that
buildPattern()never ran and the scanner emitted no.midvash-ref
elements.Fix: rewrite
/</gas/[<]/g— a character class with the same semantics,
but without the literal</sequence in source, so the host-side escape no
longer corrupts the regex. Added 3 regression tests that apply the same
</→<\/rewrite to the injected JS before evaluating, locking the
contract in: any future regex literal containing</will fail these tests
before shipping.
v0.3.0
Minor Changes
-
#52
01b5335Thanks @onetogregorio! - Client bundle: real<a href>fallback (SEO), touch support, scheme guard, aria-live.- SEO (issue #49): the client-only fallback now renders real
<a href>
anchors instead of<span>— so when a consuming site forgets to register
the SSR middleware, Googlebot still sees real links to midvash.com and link
equity flows. URLs match the SSR shape exactly (/{lang}/{version}/{slug}/ {ch}/{verse}), with the slug pre-localized server-side. Nonofollow, no
target="_blank"— by design. - Touch / mobile (issue #36): on coarse-pointer devices a single tap on a
reference opens the tooltip and blocks navigation; a second tap on the same
reference (tooltip still open) lets the click through so the user reaches
midvash.com. Tap-outside closes the tooltip. Desktop (pointer: fine)
behavior is unchanged — hover/focus still drives the tooltip, click
navigates normally. - Security defense-in-depth (issue #42):
payload.readMoreUrlis now
validated before being placed in anhref. Onlyhttp:/https:schemes
are accepted;javascript:/data:/ etc. cause the "Ler mais" link to
be omitted (the verse text still renders). - a11y (issue #38): the tooltip body is marked
aria-live="polite"/
aria-atomic="true", so screen readers announce the verse when it
replaces the "Carregando…" placeholder (follow-up to #13).
buildClientPatternis now capturing (m[1..4]= book, chapter, verse,
verseEnd) so the client can extract the parts needed to build a URL; the
non-capturing shape is no longer exported. NewbuildNameToSlughelper
exports a small name→localized-slug map alongside the pattern. - SEO (issue #49): the client-only fallback now renders real
-
#53
cf8c6e2Thanks @onetogregorio! - Tooltip distinguishes "verse not found" from "couldn't load" (issue #41).fetchVersenow returns a tagged result ({ ok: true, data } | { ok: false, kind: "not-found" | "fetch-error" }) so the plugin can tell an upstream 404
(the reference parses but doesn't exist — typically a typo like
"John 99:99") apart from a transient network/timeout/5xx failure. The
/lookuproute propagates{ error, reference, version }on failure; the
client renders the matching localized string from the newnotFoundentry
inClientStrings(added in pt-br / en / es).404 results are NOT cached, so fixing a typo and re-hovering hits the
upstream again. Other failures still aren't cached either (no behavior
change there).Breaking (internal):
fetchVerse's return type changed from
VerseResponse | nulltoVerseResult. No public re-export touches this,
so external consumers should be unaffected. -
#50
49767f6Thanks @onetogregorio! - SSR linkifier: scope references to article content, robustness + perf fixes.- Scope (issue #37): the SSR linkifier no longer wraps references inside
page chrome (<nav>,<header>,<footer>,<aside>,<head>) or non-
content widgets (<title>,<option>,<select>,<optgroup>,
<button>,<svg>,<math>,<noscript>,<iframe>). This matches the
client scanner's defaultselectors(article,.prose,.post-content,
main) and avoids sitewide-repeated links that Google reads as
over-optimization. - Robustness (issue #40): the tag scanner is now attribute-aware — a
>
inside a quoted attribute value (e.g.<img alt="2 > 1">) is correctly
ignored when seeking the tag end, so the body that follows is no longer
mis-parsed. - Perf (issue #39): a cheap probe regex runs first; pages with no
reference candidate are returned unchanged (same string instance), skipping
the full streaming parse entirely. - SEO: linkified anchors now include a
titleattribute matching the
reference (e.g.title="João 3:16") for crawler context. The plugin still
does NOT addrel="nofollow"ortarget="_blank"— link equity flows
in-document to midvash.com, by design.
This is a
minorbump because the default scope changed: references that
used to be linkified inside<nav>/<header>/<footer>(etc.) no
longer are. Sites that relied on that behavior should move the references
into article content. - Scope (issue #37): the SSR linkifier no longer wraps references inside
Patch Changes
-
#54
c78dbd7Thanks @onetogregorio! - Docs: clarify the SEO model + document 0.3.0 changes.- Reframe the SSR middleware section as "recommended" (was "optional") — SEO
is the plugin's stated goal. - Document the two-layer model: SSR middleware + client-side fallback both
produce real<a href>anchors (since 0.3.0 in the client fallback too). - List the SEO contract explicitly: no
nofollow, notarget="_blank",
titleattribute, scope limited to article content (no nav/footer/title
pollution). - Document the new mobile / touch behavior (tap-to-toggle, second-tap to
navigate). - Updates to README.md, README.pt-BR.md, README.es.md — kept in sync.
Patch-level bump (docs only).
- Reframe the SSR middleware section as "recommended" (was "optional") — SEO
v0.2.2
Patch Changes
- #46
60a792eThanks @onetogregorio! - Docs: fixCHANGELOG.mdordering — the prose intro had drifted between version
entries (Changesets prepends new versions right after the H1). Removed it so
entries stay newest-first.
v0.2.1
Patch Changes
- #43
026847fThanks @onetogregorio! - Fix ambiguous book abbreviations. "Jó" now resolves to Job (not João/John) via
an accent-aware override — plain "Jo" still resolves to João/John. "Mc" now
resolves only to Mark ("Mc" was wrongly also listed under Micah's English
abbreviations). Adds a guard test that fails if any two books ever share the same
accent-aware abbreviation.
All notable changes to @midvash/emdash-plugin-bible are documented here.
This project follows Semantic Versioning (pre-1.0: minor
bumps may include breaking changes).
v0.2.0
Changelog
All notable changes to @midvash/emdash-plugin-bible are documented here.
This project follows Semantic Versioning (pre-1.0: minor
bumps may include breaking changes).
0.2.0 — 2026-06-04
Correctness, EmDash-standards compliance, build/distribution, and a large test
suite. Breaking changes are marked.
Added
page:fragmentshook — the tooltip<script>+<style>are now
auto-injected into public pages (zero config) when the site layout renders
EmDash's<EmDashHead>/<EmDashBodyEnd>components. Requires the
hooks.page-fragments:registercapability.- i18n for tooltip strings (pt-BR / en / es), selected from the configured
content language and injected server-side. - Tests — full vitest suite (parser, linkify, books,
midvash, settings, pattern, runtime, client-assets, i18n, middleware, routes +
hooks, descriptor, and a happy-dom test that runs the real client bundle).
~97% statement / ~87% branch coverage with enforced thresholds. - CI — GitHub Actions running typecheck + tests + build + marketplace-bundle
validation on Node 20 and 22. - Build & marketplace tooling —
npm run build(tsdown →dist/),
npm run bundle/npm run bundle:validate(emdash plugin bundle). - Single source of truth for settings (
src/lib/settings.ts): defaults, admin
schema, and the Block Kit form are all derived from one table.
Changed
- BREAKING: the package now ships built
dist/(ESM +.d.ts) instead
of raw TypeScript;exportspoint todist/*. A build step runs on publish. - BREAKING: removed the default export from the entry — import the named
biblePlugin(required by theemdash plugin bundlemanifest extractor). - BREAKING: capability
network:fetch→network:request(the former is
deprecated and hard-fails marketplace publish); peeremdash→^0.16.1. - The default-version list is reconciled with the live Midvash API: 37
accurate versions across pt-BR / en / es. loadSettingsnow uses a singlekv.list("settings:")read (was ~15 point
reads), running on every route and page render.
Fixed
- BREAKING (removal): removed the
/client.jsand/client.cssroutes.
EmDash plugin routes always return JSON, so these never served real JS/CSS
assets — delivery now goes through thepage:fragmentshook (or the
getBibleByMidvashSnippetsruntime helper / SSR middleware). - Spanish NVI version slug
nvi-es→nvies(the former didn't resolve). client.css/ inline CSS no longer force the link color when Use custom
colors is off (references inherit the host site's styles).settings/saveno longer callsrequest.json()(sandboxed routes expose only
input;requesthas no body-parsing methods).- Admin form, settings schema, and runtime defaults can no longer drift
(underlineLinksdefault, missinguseCustomColors, stale version list).
Notes
- This is a trusted (in-process) plugin. EmDash does not run
page:fragments
for sandboxed plugins, so a sandboxed marketplace install exposes only the
/lookupJSON API — the hover tooltips require a trusted install (npm +
astro.config). See the README.
0.1.0
- Initial release: Bible-reference detection + hover tooltips powered by the
public Midvash API.